knitr::opts_chunk$set(message = F, warning = FALSE)

In this notebook we conduct exploratory factor analyses (EFAs) on the datasets for our studies of concepts of mental life, in which each participants judged the various mental capacities of a particular target entity. We analyze datasets for adults and children from each of our five field sites: the US, Ghana, Thailand, China, and Vanuatu.

This notebook contains secondary analyses, parallel to the results presented in the main text, in which we present orthogonal rotations rather than oblique transformations of the EFA results.

# read in data, shorten "feel sick," and limit to universal targets and questions: adults
d_us_adults <- read_csv("../data/d_us_adults.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_gh_adults <- read_csv("../data/d_gh_adults.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_th_adults <- read_csv("../data/d_th_adults.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_ch_adults <- read_csv("../data/d_ch_adults.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_vt_adults <- read_csv("../data/d_vt_adults.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))

# read in data, shorten "feel sick," and limit to universal targets and questions: children
d_us_children <- read_csv("../data/d_us_children.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_gh_children <- read_csv("../data/d_gh_children.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_th_children <- read_csv("../data/d_th_children.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_ch_children <- read_csv("../data/d_ch_children.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question))
d_vt_children <- read_csv("../data/d_vt_children.csv") %>%
  filter(target %in% levels_target_univ, question_cat == "universal") %>%
  mutate(question = gsub("\\, .*$", " \\[...\\]", question)) %>%
  # filter out participants outside of the age range
  filter((age >= 6 & age <= 12) | is.na(age))
# make wide-form datasets for EFA: adults
d_us_adults_w <- wide_df_fun(d_us_adults)
d_gh_adults_w <- wide_df_fun(d_gh_adults)
d_th_adults_w <- wide_df_fun(d_th_adults)
d_ch_adults_w <- wide_df_fun(d_ch_adults)
d_vt_adults_w <- wide_df_fun(d_vt_adults)

# make wide-form datasets for EFA: children
d_us_children_w <- wide_df_fun(d_us_children)
d_gh_children_w <- wide_df_fun(d_gh_children)
# d_gh_eng_children_w <- wide_df_fun(d_gh_eng_children)
d_th_children_w <- wide_df_fun(d_th_children)
d_ch_children_w <- wide_df_fun(d_ch_children)
d_vt_children_w <- wide_df_fun(d_vt_children)

Adults

Samples

bind_rows(d_us_adults, d_gh_adults, d_th_adults, d_ch_adults, d_vt_adults) %>%
  mutate(country = factor(country, levels = levels_country)) %>%
  distinct(country, subj_id) %>%
  count(country) %>%
  janitor::adorn_totals()
  country   n
       US 127
    Ghana 150
 Thailand 150
    China 136
  Vanuatu 148
    Total 711

Scale use

bind_rows(d_us_adults, d_gh_adults, d_th_adults, d_ch_adults, d_vt_adults) %>%
  mutate(country = factor(country, levels = levels_country),
         response_cat = recode_factor(response_cat,
                                      "no" = "no",
                                      "kind of" = "kind of",
                                      "yes" = "yes", 
                                      .missing = "missing data")) %>%
  count(country, response_cat) %>%
  complete(response_cat, nesting(country), fill = list(n = 0)) %>%
  group_by(country) %>%
  mutate(prop = n/sum(n, na.rm = T)) %>%
  ungroup() %>%
  select(-n) %>%
  spread(response_cat, prop) %>%
  janitor::adorn_pct_formatting(digits = 2)

Factor retention: parallel analysis

# NOTE: Here is distribution over outcomes of parallel analysis with 100 iterations. We'll choose the median number of factors.

if (file.exists("../results/pa_outcomes_dist_adults.RDS")) {
  
  pa_outcomes_dist_adults <- readRDS("../results/pa_outcomes_dist_adults.RDS")
  
} else {
  
  pa_outcomes_dist_adults <- data.frame(us = NULL, gh = NULL, th = NULL,
                                        ch = NULL, vt = NULL)
  
  set.seed(54321)
  n_cores <- parallel::detectCores()
  options(mc.cores = n_cores)
  
  for (i in 1:100) {
    pa_outcomes_dist_adults[i, "us"] <- fa.parallel(d_us_adults_w, plot = F)$nfact
    pa_outcomes_dist_adults[i, "gh"] <- fa.parallel(d_gh_adults_w, plot = F)$nfact     
    pa_outcomes_dist_adults[i, "th"] <- fa.parallel(d_th_adults_w, plot = F)$nfact
    pa_outcomes_dist_adults[i, "ch"] <- fa.parallel(d_ch_adults_w, plot = F)$nfact
    pa_outcomes_dist_adults[i, "vt"] <- fa.parallel(d_vt_adults_w, plot = F)$nfact
  }
  
  saveRDS(pa_outcomes_dist_adults, file = "../results/pa_outcomes_dist_adults.RDS")
}

# plot
pa_outcomes_dist_adults %>%
  rownames_to_column("iter") %>%
  gather(country, nfact, -iter) %>%
  mutate(country = factor(country,
                          levels = c("us", "gh", "th", "ch", "vt"),
                          labels = levels_country)) %>%
  ggplot(aes(x = nfact)) +
  facet_grid(~ country) +
  geom_bar(stat = "count") +
  scale_x_continuous(limits = c(1, max(pa_outcomes_dist_adults) + 1),
                     breaks = seq(0, 100, 1)) +
  labs(x = "Number of factors suggested by fa.parallel()")

Exploratory factor analysis

set.seed(54321)

# do exploratory factor analysis: adults
efa_us_adults <- fa_fun(d_us_adults_w,
                        n = median(pa_outcomes_dist_adults$us),
                        chosen_n.iter = 1000,
                        chosen_rot = "varimax")
colnames(efa_us_adults$loadings) <- paste0("usADULTS_", 
                                           colnames(efa_us_adults$loadings))

efa_gh_adults <- fa_fun(d_gh_adults_w, 
                        n = median(pa_outcomes_dist_adults$gh),
                        chosen_n.iter = 1000,
                        chosen_rot = "varimax")
colnames(efa_gh_adults$loadings) <- paste0("ghADULTS_", 
                                           colnames(efa_gh_adults$loadings))

efa_th_adults <- fa_fun(d_th_adults_w, 
                        n = median(pa_outcomes_dist_adults$th),
                        chosen_n.iter = 1000,
                        chosen_rot = "varimax")
colnames(efa_th_adults$loadings) <- paste0("thADULTS_", 
                                           colnames(efa_th_adults$loadings))

efa_ch_adults <- fa_fun(d_ch_adults_w, 
                        n = median(pa_outcomes_dist_adults$ch),
                        chosen_n.iter = 1000,
                        chosen_rot = "varimax")
colnames(efa_ch_adults$loadings) <- paste0("chADULTS_", 
                                           colnames(efa_ch_adults$loadings))

efa_vt_adults <- fa_fun(d_vt_adults_w, 
                        n = median(pa_outcomes_dist_adults$vt),
                        chosen_n.iter = 1000,
                        chosen_rot = "varimax")
colnames(efa_vt_adults$loadings) <- paste0("vtADULTS_", 
                                           colnames(efa_vt_adults$loadings))
factor_names_adults <- data.frame(factor = c(colnames(efa_us_adults$loadings),
                                             colnames(efa_gh_adults$loadings),
                                             colnames(efa_th_adults$loadings),
                                             colnames(efa_ch_adults$loadings),
                                             colnames(efa_vt_adults$loadings))) %>%
  mutate(age_group = "adults") %>%
  mutate(country = case_when(grepl("^us", factor) ~ "US",
                             grepl("^gh", factor) ~ "Ghana",
                             grepl("^th", factor) ~ "Thailand",
                             grepl("^ch", factor) ~ "China",
                             grepl("^vt", factor) ~ "Vanuatu"),
         country = factor(country, levels_country)) %>%
  mutate(factor_name = gsub("^us", "US ", factor),
         factor_name = gsub("^gh", "Gh. ", factor_name),
         factor_name = gsub("^th", "Th. ", factor_name),
         factor_name = gsub("^ch", "Ch. ", factor_name),
         factor_name = gsub("^vt", "Va. ", factor_name),
         factor_name = gsub("ADULTS", "adults", factor_name),
         factor_name = gsub("_F", " Factor ", factor_name)) %>%
  mutate(factor_descript = recode(factor,
                                  usADULTS_F1 = "Body",
                                  usADULTS_F2 = "Heart",
                                  usADULTS_F3 = "Mind",
                                  ghADULTS_F1 = "Inner sphere (mind-like)",
                                  ghADULTS_F2 = "Body-like",
                                  ghADULTS_F3 = "Interpersonal, religious",
                                  thADULTS_F1 = "Body-like",
                                  thADULTS_F2 = "Heart-like",
                                  thADULTS_F3 = "Mind-like",
                                  chADULTS_F1 = "Heart-like",
                                  chADULTS_F2 = "Body-like",
                                  chADULTS_F3 = "Mind-like",
                                  vtADULTS_F1 = "Harmony (mind-like, heart-like)",
                                  vtADULTS_F2 = "Sin (body-like)"),
         factor_labdescript = paste(gsub(".*_F", "F", factor),
                                    factor_descript, sep = ": "))

Factor loadings

# order capacities: adults
order_us_adults <- fa.sort(efa_us_adults)$loadings[] %>% rownames()
order_gh_adults <- fa.sort(efa_gh_adults)$loadings[] %>% rownames()
order_th_adults <- fa.sort(efa_th_adults)$loadings[] %>% rownames()
order_ch_adults <- fa.sort(efa_ch_adults)$loadings[] %>% rownames()
order_vt_adults <- fa.sort(efa_vt_adults)$loadings[] %>% rownames()
# compile loadings: adults
loadings_adults <- bind_rows(
  loadings_fun(efa_us_adults) %>% mutate(country = "US"),
  loadings_fun(efa_gh_adults) %>% mutate(country = "Ghana"),
  loadings_fun(efa_th_adults) %>% mutate(country = "Thailand"),
  loadings_fun(efa_ch_adults) %>% mutate(country = "China"),
  loadings_fun(efa_vt_adults) %>% mutate(country = "Vanuatu")) %>%
  mutate(country = factor(country, levels = levels_country),
         capacity_ord_us = factor(capacity, levels = order_us_adults),
         capacity_ord_gh = factor(capacity, levels = order_gh_adults),
         capacity_ord_th = factor(capacity, levels = order_th_adults),
         capacity_ord_ch = factor(capacity, levels = order_ch_adults),
         capacity_ord_vt = factor(capacity, levels = order_vt_adults)) %>%
  arrange(country, factor, desc(abs(loading)), capacity) %>%
  mutate(order = 1:nrow(.)) %>%
  left_join(factor_names_adults)
# make heatmap figure: adults
loadings_adults %>%
  mutate(factor_num = as.numeric(gsub(".*F", "", factor))) %>%
  mutate(sample = paste(country, "adults", sep = "\n")) %>%
  left_join(factor_names_adults) %>%
  mutate(country = factor(country, levels = levels_country)) %>%
  ggplot(aes(x = reorder(factor_labdescript, factor_num), 
             y = reorder(capacity, desc(capacity_ord_us)),
             # y = reorder(capacity, desc(capacity_ord_ec)), 
             # y = reorder(capacity, desc(capacity_ord_gh)),
             # y = reorder(capacity, desc(capacity_ord_th)),
             # y = reorder(capacity, desc(capacity_ord_ch)),
             # y = reorder(capacity, desc(capacity_ord_vt)),
             fill = loading)) +
  facet_grid(~ reorder(sample, as.numeric(country)), scales = "free", space = "free") +
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = format(round(loading, 2), nsmall = 2)), size = 3) +
  scale_fill_distiller(palette = "RdYlBu", limits = c(-1, 1),
                       guide = guide_colorbar(barheight = 20, barwidth = 0.5)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        panel.spacing.x = unit(0.8, "lines"),
        strip.text.x = element_text(size = 10, face = "bold")) +
  labs(x = NULL, y = "Capacity", fill = "Factor\nloading")

Congruence

cong_adults <- fa.congruence(x = list(efa_us_adults$loadings,
                                      efa_gh_adults$loadings,
                                      efa_th_adults$loadings,
                                      efa_ch_adults$loadings,
                                      efa_vt_adults$loadings),
                             digits = 5) %>%
  # get_upper_tri_fun() %>%
  data.frame() %>%
  rownames_to_column("factor_A") %>%
  gather(factor_B, cong, -factor_A) %>%
  left_join(factor_names_adults %>% 
              rename_all(list(~ (paste(., "A", sep = "_"))))) %>%
  left_join(factor_names_adults %>% 
              rename_all(list(~ (paste(., "B", sep = "_")))))
cong_adults_top_match_A <- top_match_fun(cong_adults, "country_A")
cong_adults_top_match_B <- top_match_fun(cong_adults, "country_B")
cong_adults %>%
  mutate_at(#vars(contains("labdescript")),
    vars(factor_labdescript_A),
    funs(gsub(" \\(", "\n\\(", .))) %>%
  mutate_at(#vars(contains("labdescript")),
    vars(factor_labdescript_A),
    funs(gsub("\\/", "\\/\n", .))) %>%
  # left_join(cong_adults_top_match_A %>% rename(top_match_A = top_match)) %>%
  left_join(cong_adults_top_match_B %>% rename(top_match_B = top_match)) %>%
  mutate(is_top_match = case_when(factor_A == factor_B ~ "bold.italic",
                                  # factor_A == top_match_A ~ "bold",
                                  factor_B == top_match_B ~ "bold",
                                  TRUE ~ "plain")) %>%
  # mutate(cong = ifelse(cong == 1, NA_real_, cong)) %>%
  mutate(sample_A = paste(toupper(country_A), "adults", sep = ":\n")) %>%
  mutate(sample_B = paste(toupper(country_B), "adults", sep = ":\n")) %>%
  mutate_at(vars(country_A, country_B),
            funs(factor(toupper(.), levels = toupper(levels_country)))) %>%
  ggplot(aes(x = factor_labdescript_A,
             y = reorder(factor_labdescript_B, desc(factor_labdescript_B)),
             fill = cong)) +
  facet_grid(reorder(sample_B, as.numeric(country_B)) ~ 
               reorder(sample_A, as.numeric(country_A)), 
             scales = "free", space = "free") +
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = case_when(is.na(cong) ~ "",
                                  TRUE ~ format(round(cong, 2), nsmall = 2)),
                fontface = is_top_match,
                color = is_top_match),
            size = 3, show.legend = F) +
  scale_color_manual(values = c("darkred", "darkblue", "black")) +
  scale_fill_viridis_c(option = "viridis", 
                       guide = guide_colorbar(barwidth = 25, barheight = 0.5)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        legend.position = "bottom",
        strip.text = element_text(size = 10, face = "bold")) +
  labs(x = NULL, y = NULL, fill = expression(italic(r[c])))

Bootstrapped congruence

if (file.exists("../results/cong_df_adults_orthogonal.RDS")) {
  
  cong_df_adults <- readRDS("../results/cong_df_adults_orthogonal.RDS")
  
} else {
  
  bs_adults <- loadings_adults %>%
    select(capacity, factor, loading) %>%
    spread(factor, loading) %>%
    select(-capacity) %>%
    sjstats::bootstrap(1000) 
  
  factors <- levels(factor(loadings_adults$factor))
  
  cong_df_adults <- data.frame(NULL)
  for (i in factors) {
    for (j in factors) {
      cname <- paste(i, j, sep = ".")
      temp <- bs_adults %>%
        mutate(cong = map_dbl(strap, ~lsa::cosine(as.data.frame(.x)[,i],
                                                  as.data.frame(.x)[,j])))
      cong_df_adults[1:1000, cname] <- temp$cong
    }
  }
  
  cong_df_adults <- cong_df_adults %>%
    gather(factor_pair, cong) %>%
    separate(factor_pair, into = c("factor_A", "factor_B"), sep = "\\.") %>%
    group_by(factor_A, factor_B) %>%
    summarise(mean = mean(cong),
              ci_lower = ci_lower(cong),
              ci_upper = ci_upper(cong)) %>%
    ungroup() %>%
    left_join(factor_names_adults %>%
                rename_all(funs(paste(., "A", sep = "_")))) %>%
    left_join(factor_names_adults %>%
                rename_all(funs(paste(., "B", sep = "_"))))
  
  rm(i, j, cname, temp, factors)
  
  saveRDS(cong_df_adults, file = "../results/cong_df_adults_orthogonal.RDS")
}
# find minimum value to set constant lower bound of plots
min_cong_adults <- cong_df_adults %>%
  summarise(min_cong = min(ci_lower, na.rm = T))
# FIGURE 3
cong_plot_fun(cong_df = cong_df_adults, which_country = "US") +
  ylim(min_cong_adults$min_cong, 1) +
  # ylim(NA, 1) +
  labs(x = NULL)

ggsave("../figures/fig03_orthogonal.png")
# FIGURE S1
cong_plot_fun(cong_df = cong_df_adults %>%
                mutate_at(#vars(contains("labdescript")),
                  vars(factor_labdescript_A),
                  funs(gsub(" \\(", "\n\\(", .))) %>%
                mutate_at(#vars(contains("labdescript")),
                  vars(factor_labdescript_A),
                  funs(gsub("\\/", "\\/\n", .))), 
              which_country = "Ghana") +
  ylim(min_cong_adults$min_cong, 1)

ggsave("../figures/figS01_orthogonal.png")
# FIGURE S2
cong_plot_fun(cong_df = cong_df_adults, 
              which_country = "Thailand") +
  ylim(min_cong_adults$min_cong, 1)

ggsave("../figures/figS02_orthogonal.png")
# FIGURE S3
cong_plot_fun(cong_df = cong_df_adults, 
              which_country = "China") +
  ylim(min_cong_adults$min_cong, 1)

ggsave("../figures/figS03_orthogonal.png")
# FIGURE S4
cong_plot_fun(cong_df = cong_df_adults %>%
                mutate_at(#vars(contains("labdescript")),
                  vars(factor_labdescript_A),
                  funs(gsub(" \\(", "\n\\(", .))) %>%
                mutate_at(#vars(contains("labdescript")),
                  vars(factor_labdescript_A),
                  funs(gsub("\\/", "\\/\n", .))), 
              which_country = "Vanuatu") +
  ylim(min_cong_adults$min_cong, 1)

ggsave("../figures/figS04_orthogonal.png")
# "In each sample, there was a factor that was similar to US adults’ “body” factor...
cong_df_adults %>% 
  filter(grepl("body", tolower(factor_descript_A)), 
         grepl("body", tolower(factor_descript_B)),
         country_A != "US", country_B == "US")

# "...and not similar to the US adult “mind” factor, ...
cong_df_adults %>% 
  filter(grepl("body", tolower(factor_descript_A)), 
         grepl("mind", tolower(factor_descript_B)),
         country_A != "US", country_B == "US")

# "... and a factor that was much more similar to US adults’ “mind” factor...
cong_df_adults %>% 
  filter(grepl("mind", tolower(factor_descript_A)), 
         grepl("mind", tolower(factor_descript_B)),
         country_A != "US", country_B == "US")

# "...than the US adult “body” factor."
cong_df_adults %>% 
  filter(grepl("mind", tolower(factor_descript_A)), 
         grepl("body", tolower(factor_descript_B)),
         country_A != "US", country_B == "US")
cong_df_adults %>% 
  filter(grepl("heart", tolower(factor_descript_A)), 
         grepl("heart", tolower(factor_descript_B)),
         country_A %in% c("Thailand", "China"), country_B == "US")

cong_df_adults %>% 
  filter(grepl("body", tolower(factor_descript_A)) | 
           grepl("mind", tolower(factor_descript_A)),
         grepl("heart", tolower(factor_descript_B)),
         country_A %in% c("Thailand", "China"), country_B == "US")

Children

Samples

bind_rows(d_us_children, d_gh_children, d_th_children, d_ch_children, d_vt_children) %>%
  mutate(country = factor(country, levels = levels_country)) %>%
  distinct(country, subj_id) %>%
  count(country) %>% 
  janitor::adorn_totals()
  country   n
       US 117
    Ghana 150
 Thailand 152
    China 131
  Vanuatu 143
    Total 693

Scale use

bind_rows(d_us_children, d_gh_children, d_th_children, d_ch_children, d_vt_children) %>%
  mutate(country = factor(country, levels = levels_country),
         response_cat = recode_factor(response_cat,
                                      "no" = "no",
                                      "kind of" = "kind of",
                                      "yes" = "yes", 
                                      .missing = "missing data")) %>%
  count(country, response_cat) %>%
  complete(response_cat, nesting(country), fill = list(n = 0)) %>%
  group_by(country) %>%
  mutate(prop = n/sum(n, na.rm = T)) %>%
  ungroup() %>%
  select(-n) %>%
  spread(response_cat, prop) %>%
  janitor::adorn_pct_formatting(digits = 2)

Factor retention: parallel analysis

# Here's the distribution over outcomes of parallel analysis with 100 iterations. We'll choose the median number of factors.

if (file.exists("../results/pa_outcomes_dist_children.RDS")) {
  
  pa_outcomes_dist_children <- readRDS("../results/pa_outcomes_dist_children.RDS")
  
} else {
  
  pa_outcomes_dist_children <- data.frame(us = NULL, gh = NULL, th = NULL,
                                          ch = NULL, vt = NULL)
  
  set.seed(54321)
  n_cores <- parallel::detectCores()
  options(mc.cores = n_cores)
  
  for (i in 1:100) {
    pa_outcomes_dist_children[i, "us"] <- fa.parallel(d_us_children_w, plot = F)$nfact
    pa_outcomes_dist_children[i, "gh"] <- fa.parallel(d_gh_children_w, plot = F)$nfact     
    pa_outcomes_dist_children[i, "th"] <- fa.parallel(d_th_children_w, plot = F)$nfact
    pa_outcomes_dist_children[i, "ch"] <- fa.parallel(d_ch_children_w, plot = F)$nfact
    pa_outcomes_dist_children[i, "vt"] <- fa.parallel(d_vt_children_w, plot = F)$nfact
  }
  
  saveRDS(pa_outcomes_dist_children, file = "../results/pa_outcomes_dist_children.RDS")
}

# plot
pa_outcomes_dist_children %>%
  rownames_to_column("iter") %>%
  gather(country, nfact, -iter) %>%
  mutate(country = factor(country,
                          levels = c("us", "gh", "th", "ch", "vt"),
                          labels = levels_country)) %>%
  ggplot(aes(x = nfact)) +
  facet_grid(~ country) +
  geom_bar(stat = "count") +
  scale_x_continuous(limits = c(1, max(pa_outcomes_dist_children) + 1),
                     breaks = seq(0, 100, 1)) +
  labs(x = "Number of factors suggested by fa.parallel()")

Exploratory factor analysis

set.seed(54321)

# do exploratory factor analysis: children
efa_us_children <- fa_fun(d_us_children_w, 
                          n = median(pa_outcomes_dist_children$us),
                          chosen_n.iter = 1000,
                          chosen_rot = "varimax")
colnames(efa_us_children$loadings) <- paste0("usCHILDREN_", 
                                             colnames(efa_us_children$loadings))

efa_gh_children <- fa_fun(d_gh_children_w,
                          n = median(pa_outcomes_dist_children$gh),
                          chosen_n.iter = 1000,
                          chosen_rot = "varimax")
colnames(efa_gh_children$loadings) <- paste0("ghCHILDREN_", 
                                             colnames(efa_gh_children$loadings))

efa_th_children <- fa_fun(d_th_children_w, 
                          n = median(pa_outcomes_dist_children$th),
                          chosen_n.iter = 1000,
                          chosen_rot = "varimax")
colnames(efa_th_children$loadings) <- paste0("thCHILDREN_", 
                                             colnames(efa_th_children$loadings))

efa_ch_children <- fa_fun(d_ch_children_w, 
                          n = median(pa_outcomes_dist_children$ch),
                          chosen_n.iter = 1000,
                          chosen_rot = "varimax")
colnames(efa_ch_children$loadings) <- paste0("chCHILDREN_", 
                                             colnames(efa_ch_children$loadings))

efa_vt_children <- fa_fun(d_vt_children_w, 
                          n = median(pa_outcomes_dist_children$vt),
                          chosen_n.iter = 1000,
                          chosen_rot = "varimax")
colnames(efa_vt_children$loadings) <- paste0("vtCHILDREN_", 
                                             colnames(efa_vt_children$loadings))
factor_names_children <- data.frame(factor = c(colnames(efa_us_children$loadings),
                                               colnames(efa_gh_children$loadings),
                                               colnames(efa_th_children$loadings),
                                               colnames(efa_ch_children$loadings),
                                               colnames(efa_vt_children$loadings))) %>%
  mutate(age_group = "children") %>%
  mutate(country = case_when(grepl("^us", factor) ~ "US",
                             grepl("^gh", factor) ~ "Ghana",
                             grepl("^th", factor) ~ "Thailand",
                             grepl("^ch", factor) ~ "China",
                             grepl("^vt", factor) ~ "Vanuatu"),
         country = factor(country, levels_country)) %>%
  mutate(factor_name = gsub("^us", "US ", factor),
         factor_name = gsub("^gh", "Gh. ", factor_name),
         factor_name = gsub("^th", "Th. ", factor_name),
         factor_name = gsub("^ch", "Ch. ", factor_name),
         factor_name = gsub("^vt", "Va. ", factor_name),
         factor_name = gsub("CHILDREN", "children", factor_name),
         factor_name = gsub("_F", " Factor ", factor_name)) %>%
  mutate(factor_descript = recode(factor,
                                  usCHILDREN_F1 = "Body-like, negative",
                                  usCHILDREN_F3 = "Heart-like, positive",
                                  usCHILDREN_F2 = "Mind-like",
                                  ghCHILDREN_F1 = "Body-like, negative",
                                  ghCHILDREN_F2 = "Mind-like, positive",
                                  ghCHILDREN_F3 = "Pray, add, etc.",
                                  thCHILDREN_F1 = "Body-like, positive",
                                  thCHILDREN_F2 = "Heart-like, negative",
                                  thCHILDREN_F3 = "Mind-like",
                                  thCHILDREN_F4 = "Add, pray, etc.",
                                  chCHILDREN_F1 = "Heart-like",
                                  chCHILDREN_F2 = "Body-like",
                                  chCHILDREN_F3 = "Mind-like",
                                  chCHILDREN_F4 = "Pray, etc.",
                                  vtCHILDREN_F1 = "Body-like",
                                  vtCHILDREN_F2 = "Mind-like, positive",
                                  vtCHILDREN_F3 = "Heart-like, negative"),
         factor_labdescript = paste(gsub(".*_F", "F", factor),
                                    factor_descript, sep = ": "))

Factor loadings

# order capacities: children
order_us_children <- fa.sort(efa_us_children)$loadings[] %>% rownames()
order_gh_children <- fa.sort(efa_gh_children)$loadings[] %>% rownames()
order_th_children <- fa.sort(efa_th_children)$loadings[] %>% rownames()
order_ch_children <- fa.sort(efa_ch_children)$loadings[] %>% rownames()
order_vt_children <- fa.sort(efa_vt_children)$loadings[] %>% rownames()
# compile loadings: children
loadings_children <- bind_rows(
  loadings_fun(efa_us_children) %>% mutate(country = "US"),
  loadings_fun(efa_gh_children) %>% mutate(country = "Ghana"),
  loadings_fun(efa_th_children) %>% mutate(country = "Thailand"),
  loadings_fun(efa_ch_children) %>% mutate(country = "China"),
  loadings_fun(efa_vt_children) %>% mutate(country = "Vanuatu")) %>%
  mutate(country = factor(country, levels = levels_country),
         capacity_ord_us = factor(capacity, levels = order_us_children),
         capacity_ord_gh = factor(capacity, levels = order_gh_children),
         capacity_ord_th = factor(capacity, levels = order_th_children),
         capacity_ord_ch = factor(capacity, levels = order_ch_children),
         capacity_ord_vt = factor(capacity, levels = order_vt_children)) %>%
  arrange(country, factor, desc(abs(loading)), capacity) %>%
  mutate(order = 1:nrow(.)) %>%
  left_join(factor_names_children)
# make heatmap figure: children
loadings_children %>%
  mutate(factor_num = as.numeric(gsub(".*F", "", factor))) %>%
  mutate(sample = paste(country, "children", sep = "\n")) %>%
  left_join(factor_names_children) %>%
  mutate(country = factor(country, levels = levels_country)) %>%
  ggplot(aes(x = reorder(factor_labdescript, factor_num), 
             y = reorder(capacity, desc(capacity_ord_us)),
             # y = reorder(capacity, desc(capacity_ord_ec)), 
             # y = reorder(capacity, desc(capacity_ord_gh)),
             # y = reorder(capacity, desc(capacity_ord_th)),
             # y = reorder(capacity, desc(capacity_ord_ch)),
             # y = reorder(capacity, desc(capacity_ord_vt)),
             fill = loading)) +
  facet_grid(~ reorder(sample, as.numeric(country)), scales = "free", space = "free") +
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = format(round(loading, 2), nsmall = 2)), size = 3) +
  scale_fill_distiller(palette = "RdYlBu", limits = c(-1, 1),
                       guide = guide_colorbar(barheight = 20, barwidth = 0.5)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        panel.spacing.x = unit(0.8, "lines"),
        strip.text.x = element_text(size = 10, face = "bold")) +
  labs(x = NULL, y = "Capacity", fill = "Factor\nloading")

Congruence

See All samples, below.

Bootstrapped congruence

if (file.exists("../results/cong_df_children_orthogonal.RDS")) {
  
  cong_df_children <- readRDS("../results/cong_df_children_orthogonal.RDS")
  
} else {
  
  bs_children <- loadings_children %>%
    select(capacity, factor, loading) %>%
    spread(factor, loading) %>%
    full_join(loadings_adults %>%
                select(capacity, factor, loading) %>%
                spread(factor, loading)) %>%
    select(-capacity) %>%
    sjstats::bootstrap(1000) 
  
  cong_df_children <- data.frame(NULL)
  
  for (k in levels_country) {
    
    factors_children <- levels(factor(loadings_children$factor[
      loadings_children$country == k]))
    factors_adults <- levels(factor(loadings_adults$factor[
      loadings_adults$country == k]))
    
    for (i in factors_children) {
      for (j in factors_adults) {
        cname <- paste(i, j, sep = ".")
        temp <- bs_children %>%
          mutate(cong = map_dbl(strap, ~lsa::cosine(as.data.frame(.x)[,i],
                                                    as.data.frame(.x)[,j])))
        cong_df_children[1:1000, cname] <- temp$cong
      }
    }
    
    rm(i, j, cname, temp, factors_children, factors_adults)
    
  }
  
  rm(k)
  
  cong_df_children <- cong_df_children %>%
    gather(factor_pair, cong) %>%
    separate(factor_pair, into = c("factor_A", "factor_B"), sep = "\\.") %>%
    group_by(factor_A, factor_B) %>%
    summarise(mean = mean(cong),
              ci_lower = ci_lower(cong),
              ci_upper = ci_upper(cong)) %>%
    ungroup() %>%
    full_join(factor_names_children %>%
                rename_all(funs(paste(., "A", sep = "_")))) %>%
    full_join(factor_names_adults %>%
                rename_all(funs(paste(., "B", sep = "_")))) %>%
    mutate(factor_bhm_A = case_when(
      grepl("body", tolower(factor_descript_A)) ~ "Body-like\nchild factor",
      grepl("mind", tolower(factor_descript_A)) ~ "Mind-like\nchild factor",
      grepl("heart", tolower(factor_descript_A)) ~ "Heart-like\nchild factor",
      TRUE ~ "Other")) %>%
    mutate(factor_bhm_B = case_when(
      grepl("body", tolower(factor_descript_B)) ~ "Local adults:\nBody-like factor",
      grepl("mind", tolower(factor_descript_B)) ~ "Local adults:\nMind-like factor",
      grepl("heart", tolower(factor_descript_B)) ~ "Local adults:\nHeart-like factor",
      TRUE ~ "Local adults:\nOther factor"))
  
  saveRDS(cong_df_children, file = "../results/cong_df_children_orthogonal.RDS")
}
# find minimum value to set constant lower bound of plots
min_cong_children <- cong_df_children %>%
  summarise(min_cong = min(ci_lower, na.rm = T))
# FIGURE 4
# fig.asp chosen to keep absolute height of y-axis relatively similar across adults and children
cong_df_children %>%
  mutate(region_A = case_when(
    country_A == "US" ~ "SF Bay Area",
    country_A == "Ghana" ~ "Cape Coast",
    country_A == "Thailand" ~ "Chiang Mai",
    country_A == "China" ~ "Shanghai",
    country_A == "Vanuatu" ~ "PV & Malekula")) %>%
  mutate(sample_A = paste(country_A, age_group_A, sep = "\n")) %>%
  mutate(lab_A = paste(paste0(region_A, ","), 
                       paste0(toupper(country_A), ":"), 
                       age_group_A, sep = "\n")) %>%
  mutate(bhm_A = case_when(
    grepl("body", tolower(factor_labdescript_A)) ~ "body",
    grepl("mind", tolower(factor_labdescript_A)) ~ "mind",
    grepl("heart", tolower(factor_labdescript_A)) ~ "heart", 
    TRUE ~ "other")) %>%
  mutate(bhm_A = factor(bhm_A, levels = c("body", "heart", "mind", "other"))) %>%
  ggplot(aes(x = reorder(factor_labdescript_A, as.numeric(bhm_A)), y = mean)) +
  facet_grid(factor_bhm_B ~ reorder(lab_A, as.numeric(country_A)), 
             scales = "free_x", space = "free_x") +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = 0.85,
           fill = "gray20", alpha = 0.2) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = 0.85, ymax = 0.95,
           fill = viridisLite::viridis(2, begin = 0.75/2, end = 0.75)[1], alpha = 0.2) +
  annotate("rect", xmin = -Inf, xmax = Inf, ymin = 0.95, ymax = Inf,
           fill = viridisLite::viridis(2, begin = 0.75/2, end = 0.75)[2], alpha = 0.2) +
  geom_hline(yintercept = 0.85, lty = 2, color = "gray10") +
  geom_hline(yintercept = 0.95, lty = 2, color = "gray10") +
  geom_pointrange(aes(ymin = ci_lower, ymax = ci_upper),
                  fatten = 3,
                  show.legend = F) +
  geom_text(aes(label = format(round(mean, 2), nsmall = 2),
                y = ifelse(ci_lower < 0.2, ci_upper + 0.05, ci_lower - 0.05),
                vjust = ifelse(ci_lower < 0.2, 0, 1))) +
  scale_y_continuous(breaks = seq(-1, 1, 0.2),
                     expand = expansion(add = 0.05)) +
  scale_color_brewer(palette = "Dark2", aesthetics = c("color", "fill")) +
  scale_shape_manual(values = 21:25) +
  labs(x = NULL,
       y = expression("Similarity "(italic(r[c])))) + 
  guides(color = "none", fill = "none") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        legend.position = "right",
        panel.border = element_rect(fill = scales::alpha("white", 0), color = "black"),
        strip.text = element_text(size = 10, face = "bold"), 
        plot.margin = unit(c(5.5, 5.5, 5.5, 15.5), "point"))

ggsave("../figures/fig04_orthogonal.png")
# "In each sample, there was a factor that was much more similar to local adults’ “body-like” factor...
cong_df_children %>% 
  filter(grepl("body", tolower(factor_bhm_A)), 
         grepl("body", tolower(factor_bhm_B)))

# "...than their “mind-like” factor, ...
cong_df_children %>% 
  filter(grepl("body", tolower(factor_bhm_A)), 
         grepl("mind", tolower(factor_bhm_B)))

# "... and a factor that was much more similar to local adults’ “mind-like” factor...
cong_df_children %>% 
  filter(grepl("mind", tolower(factor_bhm_A)), 
         grepl("mind", tolower(factor_bhm_B)))

# "...than their “body-like” factor."
cong_df_children %>% 
  filter(grepl("mind", tolower(factor_bhm_A)), 
         grepl("body", tolower(factor_bhm_B)))

All samples

Congruence

cong_all <- fa.congruence(x = list(efa_us_adults$loadings,
                                   efa_gh_adults$loadings,
                                   efa_th_adults$loadings,
                                   efa_ch_adults$loadings,
                                   efa_vt_adults$loadings,
                                   efa_us_children$loadings,
                                   efa_gh_children$loadings,
                                   efa_th_children$loadings,
                                   efa_ch_children$loadings,
                                   efa_vt_children$loadings),
                          digits = 5) %>%
  # get_upper_tri_fun() %>%
  data.frame() %>%
  rownames_to_column("factor_A") %>%
  gather(factor_B, cong, -factor_A) %>%
  left_join(bind_rows(factor_names_adults %>% 
                        rename_all(funs(paste(., "A", sep = "_"))),
                      factor_names_children %>%
                        rename_all(funs(paste(., "A", sep = "_"))))) %>%
  left_join(bind_rows(factor_names_adults %>% 
                        rename_all(funs(paste(., "B", sep = "_"))),
                      factor_names_children %>%
                        rename_all(funs(paste(., "B", sep = "_")))))
# make wide-form version of df
cong_all_w <- cong_all %>%
  select(factor_A, factor_B, cong) %>%
  spread(factor_B, cong) %>%
  column_to_rownames("factor_A")

# treat similarity matrix as if it were the correlation matrix for hclust
row.order <- hclust(as.dist((1 - cong_all_w)/2))$order
col.order <- hclust(as.dist(t((1 - cong_all_w)/2)))$order

# re-order matrix accoring to clustering
cong_all_w <- cong_all_w[row.order, col.order] 

# for some reason reshape2::melt() works better than current tidyverse functions...
cong_all_ordered <- melt(as.matrix(cong_all_w)) %>%
  rename(factor_A_ordered = Var1, 
         factor_B_ordered = Var2,
         cong = value) %>%
  mutate(factor_A = as.character(factor_A_ordered),
         factor_B = as.character(factor_B_ordered)) %>%
  full_join(cong_all %>% select(contains("_A")) %>% distinct()) %>%
  full_join(cong_all %>% select(contains("_B")) %>% distinct()) %>%
  mutate(lab_A = paste(paste(country_A, age_group_A), factor_labdescript_A, sep = ", "),
         lab_B = paste(paste(country_B, age_group_B), factor_labdescript_B, sep = ", "))
# mutate(sample_A = paste(country_A, age_group_A, sep = ", "),
#        sample_B = paste(country_B, age_group_B, sep = ", "),
#        lab_A = paste(sample_A, factor_labdescript_A, sep = " "),
#        lab_B = paste(sample_B, factor_labdescript_B, sep = " "))
# FIGURE 2
cong_lower_lim <- ifelse(min(cong_all_ordered$cong) > -0.05, -0.05, 
                         min(cong_all_ordered$cong))
# cong_plot_colors <- c("red4", "blue4", "darkorchid4", "black")
# cong_plot_colors <- c("black", "black", "black", "black")
cong_plot_colors <- c("red4", "red4", "red4", "black")

cong_all_ordered %>%
  ggplot(aes(x = reorder(lab_A, as.numeric(factor_A_ordered)),
             y = reorder(lab_B, as.numeric(desc(factor_B_ordered))),
             fill = cong)) + 
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = format(round(cong, 2), nsmall = 2),
                color = case_when(cong > 0.85 ~ "a", 
                                  cong > 0.75 ~ "b",
                                  cong > 0.65 ~ "c",
                                  TRUE ~ "d")),
            show.legend = F) +
  # body-like factors
  annotate("rect", xmin = 5.5, xmax = 15.5, ymin = 16.5, ymax = 26.5,
           color = cong_plot_colors[1], size = 1.5, alpha = 0) +
  # mind-like factors
  annotate("rect", xmin = 15.5, xmax = 25.5, ymin = 6.5, ymax = 16.5,
           color = cong_plot_colors[2], size = 1.5, alpha = 0) +
  # heart-like factors
  annotate("rect", xmin = 25.5, xmax = 31.5, ymin = 0.5, ymax = 6.5,
           color = cong_plot_colors[3], size = 1.5, alpha = 0) +
  # scale_fill_viridis_c(trans = scales::exp_trans(base = exp(1)),
  #                      limits = c(cong_lower_lim, 1), 
  #                      breaks = seq(cong_lower_lim, 1, 0.05),
  #                      labels = c(format(seq(cong_lower_lim, 0.8, 0.05), nsmall = 2),
  #                                 "0.85 = moderate", "0.90", 
  #                                 "0.95 = high", "1.00"),
  #                      option = "viridis",
  #                      guide = guide_colorbar(barheight = 40)) +
  scale_fill_gradientn(#trans = scales::exp_trans(base = exp(1)),
    limits = c(cong_lower_lim, 1), 
    breaks = seq(cong_lower_lim, 1, 0.05),
    labels = c(format(seq(cong_lower_lim, 0.8, 0.05), nsmall = 2),
               "0.85 = moderate", "0.90", 
               "0.95 = high", "1.00"),
    colors = viridisLite::viridis(6),
    values = c(0, 0.65, 0.75, 0.85, 0.95, 1),
    guide = guide_colorbar(barheight = 40)) +
  scale_color_manual(values = c("black", "black", "black", "gray60")) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(
      # angle = 45, hjust = 1, vjust = 1,
      angle = 90, hjust = 1, vjust = 1,
      size = size_fun(cong_all_ordered$lab_A, sizes = c(20, 14)),
      color = color_fun(cong_all_ordered$lab_A, color_list = cong_plot_colors),
      face  = face_fun(cong_all_ordered$lab_A)),
    axis.text.y = element_text(
      size = rev(size_fun(cong_all_ordered$lab_A, sizes = c(20, 14))),
      color = rev(color_fun(cong_all_ordered$lab_A, color_list = cong_plot_colors)),
      face  = rev(face_fun(cong_all_ordered$lab_A))),
    legend.title = element_text(face = "bold", size = 20),
    # axis.ticks = element_line(size = 0.5),
    axis.ticks.x = element_line(
      size = size_fun(cong_all_ordered$lab_A, sizes = c(1.5, 0.5)),
      color = color_fun(cong_all_ordered$lab_A, color_list = cong_plot_colors)),
    axis.ticks.y = element_line(
      size = rev(size_fun(cong_all_ordered$lab_A, sizes = c(1.5, 0.5))),
      color = rev(color_fun(cong_all_ordered$lab_A, color_list = cong_plot_colors))),
    axis.ticks.length = unit(0.25, "cm")) +
  labs(x = NULL, y = NULL, fill = expression(italic(r[c])))

ggsave("../figures/fig02_orthogonal.png")

Jaccard Similarity

strong_load_all <- loadings_adults %>%
  bind_rows(loadings_children) %>%
  select(country, age_group, factor, capacity, loading) %>%
  mutate(strong_load = ifelse(loading >= 0.5, 1, 0)) %>%
  select(-loading)

cross_load_all <- strong_load_all %>%
  filter(strong_load == 1) %>%
  count(country, age_group, capacity, strong_load) %>%
  filter(n > 1) %>%
  mutate(cross_load = T) %>%
  select(country, age_group, capacity, cross_load)

strong_noncross_load_all <- strong_load_all %>%
  left_join(cross_load_all) %>%
  filter(is.na(cross_load))

jaccard_all <- strong_noncross_load_all %>%
  select(factor, capacity, strong_load) %>%
  spread(factor, strong_load) %>%
  column_to_rownames("capacity") %>%
  t() %>%
  dist(method = "binary", diag = T, upper = T) %>%
  as.matrix() %>%
  data.frame() %>%
  rownames_to_column("factor_A") %>%
  gather(factor_B, jaccard, -factor_A) %>%
  # compute similarity index instead of distance
  mutate(jaccard = 1 - jaccard) %>%
  left_join(bind_rows(factor_names_adults %>% 
                        rename_all(funs(paste(., "A", sep = "_"))),
                      factor_names_children %>%
                        rename_all(funs(paste(., "A", sep = "_"))))) %>%
  left_join(bind_rows(factor_names_adults %>% 
                        rename_all(funs(paste(., "B", sep = "_"))),
                      factor_names_children %>%
                        rename_all(funs(paste(., "B", sep = "_")))))
# make wide-form version of df
jaccard_all_w <- jaccard_all %>%
  select(factor_A, factor_B, jaccard) %>%
  spread(factor_B, jaccard) %>%
  column_to_rownames("factor_A")

# treat distance matrix as if it were the correlation matrix for hclust
row.order <- hclust(as.dist((1 - jaccard_all_w)/2))$order
col.order <- hclust(as.dist(t((1 - jaccard_all_w)/2)))$order

# re-order matrix accoring to clustering
jaccard_all_w <- jaccard_all_w[row.order, col.order] 

# for some reason reshape2::melt() works better than current tidyverse functions...
jaccard_all_ordered <- melt(as.matrix(jaccard_all_w)) %>%
  rename(factor_A_ordered = Var1, 
         factor_B_ordered = Var2,
         jaccard = value) %>%
  mutate(factor_A = as.character(factor_A_ordered),
         factor_B = as.character(factor_B_ordered)) %>%
  full_join(jaccard_all %>% select(contains("_A")) %>% distinct()) %>%
  full_join(jaccard_all %>% select(contains("_B")) %>% distinct()) %>%
  mutate(lab_A = paste(paste(country_A, age_group_A), factor_labdescript_A, sep = ", "),
         lab_B = paste(paste(country_B, age_group_B), factor_labdescript_B, sep = ", "))
# mutate(sample_A = paste(country_A, age_group_A, sep = ", "),
#        sample_B = paste(country_B, age_group_B, sep = ", "),
#        lab_A = paste(sample_A, factor_labdescript_A, sep = " "),
#        lab_B = paste(sample_B, factor_labdescript_B, sep = " "))
# FIGURE 2 equivalent
jaccard_lower_lim <- ifelse(min(jaccard_all_ordered$jaccard) > 0, 0, 
                         min(jaccard_all_ordered$jaccard))
# jaccard_plot_colors <- c("red4", "blue4", "darkorchid4", "black")
# jaccard_plot_colors <- c("black", "black", "black", "black")
jaccard_plot_colors <- c("red4", "red4", "red4", "black")

jaccard_all_ordered %>%
  ggplot(aes(x = reorder(lab_A, as.numeric(factor_A_ordered)),
             y = reorder(lab_B, as.numeric(desc(factor_B_ordered))),
             fill = jaccard)) + 
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = case_when(
    # jaccard %in% c(0, 1) ~ format(round(jaccard, 0), nsmall = 0),
    TRUE ~ format(round(jaccard, 2), nsmall = 2)),
    color = case_when(jaccard >= 0.75 ~ "a", 
                      jaccard >= 0.5 ~ "b",
                      jaccard >= 0.25 ~ "c",
                      TRUE ~ "d")),
    show.legend = F) +
  # mind-like and other factors
  annotate("rect", xmin = 0.5, xmax = 14.5, ymin = 17.5, ymax = 31.5,
           color = jaccard_plot_colors[2], size = 1.5, alpha = 0) +
  # body-like factors
  annotate("rect", xmin = 14.5, xmax = 24.5, ymin = 7.5, ymax = 17.5,
           color = jaccard_plot_colors[1], size = 1.5, alpha = 0) +
  # heart-like factors
  annotate("rect", xmin = 24.5, xmax = 31.5, ymin = 0.5, ymax = 7.5,
           color = jaccard_plot_colors[3], size = 1.5, alpha = 0) +
  scale_fill_viridis_c(#trans = scales::exp_trans(base = exp(1)),
                       limits = c(jaccard_lower_lim, 1),
                       breaks = seq(jaccard_lower_lim, 1, 0.05),
                       # labels = c(format(seq(jaccard_lower_lim, 0.8, 0.05), 
                       #                   nsmall = 2),
                       #            "0.85 = moderate", "0.90",
                       #            "0.95 = high", "1.00"),
                       option = "viridis", 
                       # direction = -1,
                       guide = guide_colorbar(barheight = 40)) +
  # scale_fill_gradientn(#trans = scales::exp_trans(base = exp(1)),
  #   limits = c(jaccard_lower_lim, 1), 
  #   breaks = seq(jaccard_lower_lim, 1, 0.05),
  #   labels = c(format(seq(jaccard_lower_lim, 0.8, 0.05), nsmall = 2),
  #              "0.85 = moderate", "0.90", 
  #              "0.95 = high", "1.00"),
  #   colors = viridisLite::viridis(6),
  #   values = c(0, 0.65, 0.75, 0.85, 0.95, 1),
  #   guide = guide_colorbar(barheight = 40)) +
  scale_color_manual(values = c("black", "black", "black", "gray60")) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(
      # angle = 45, hjust = 1, vjust = 1,
      angle = 90, hjust = 1, vjust = 1,
      size = size_fun(jaccard_all_ordered$lab_A, sizes = c(20, 14)),
      color = color_fun(jaccard_all_ordered$lab_A, color_list = jaccard_plot_colors),
      face  = face_fun(jaccard_all_ordered$lab_A)),
    axis.text.y = element_text(
      size = rev(size_fun(jaccard_all_ordered$lab_A, sizes = c(20, 14))),
      color = rev(color_fun(jaccard_all_ordered$lab_A, color_list = jaccard_plot_colors)),
      face  = rev(face_fun(jaccard_all_ordered$lab_A))),
    legend.title = element_text(face = "bold", size = 20),
    # axis.ticks = element_line(size = 0.5),
    axis.ticks.x = element_line(
      size = size_fun(jaccard_all_ordered$lab_A, sizes = c(1.5, 0.5)),
      color = color_fun(jaccard_all_ordered$lab_A, color_list = jaccard_plot_colors)),
    axis.ticks.y = element_line(
      size = rev(size_fun(jaccard_all_ordered$lab_A, sizes = c(1.5, 0.5))),
      color = rev(color_fun(jaccard_all_ordered$lab_A, color_list = jaccard_plot_colors))),
    axis.ticks.length = unit(0.25, "cm")) +
  labs(x = NULL, y = NULL, fill = "Jaccard\nsimilarity")

ggsave("../figures/fig02_orthogonal_jaccard.png")

Developmental comparisons

# FIGURE S5, FIGURE S6, FIGURE S7, FIGURE S8, FIGURE S9
plot_grid(heatmap_comp_fun(
  efa_list = list(efa_us_adults, efa_us_children), padding = F),
  dev_cong_plot_fun(cong_df_children, which_country = "US", padding = T),
  ncol = 1, rel_heights = c(2, 1.5), labels = "AUTO")

ggsave("../figures/figS05_orthogonal.png")

plot_grid(heatmap_comp_fun(
  efa_list = list(efa_gh_adults, efa_gh_children), padding = F),
  dev_cong_plot_fun(cong_df_children, which_country = "Ghana", padding = T),
  ncol = 1, rel_heights = c(2, 1.5), labels = "AUTO")

ggsave("../figures/figS06_orthogonal.png")

plot_grid(heatmap_comp_fun(
  efa_list = list(efa_th_adults, efa_th_children), padding = F),
  dev_cong_plot_fun(cong_df_children, which_country = "Thailand", padding = T),
  ncol = 1, rel_heights = c(2, 1.5), labels = "AUTO")

ggsave("../figures/figS07_orthogonal.png")

plot_grid(heatmap_comp_fun(
  efa_list = list(efa_ch_adults, efa_ch_children), padding = F),
  dev_cong_plot_fun(cong_df_children, which_country = "China", padding = T),
  ncol = 1, rel_heights = c(2, 1.5), labels = "AUTO")

ggsave("../figures/figS08_orthogonal.png")

plot_grid(heatmap_comp_fun(
  efa_list = list(efa_vt_adults, efa_vt_children), padding = F),
  dev_cong_plot_fun(cong_df_children, which_country = "Vanuatu", padding = T),
  ncol = 1, rel_heights = c(2, 1.5), labels = "AUTO")

ggsave("../figures/figS09_orthogonal.png")
# FIGURE 1, version 1
heatmap_comp_fun(list(efa_us_adults, efa_gh_adults, efa_th_adults, 
                      efa_ch_adults, efa_vt_adults, 
                      efa_us_children, efa_gh_children, efa_th_children, 
                      efa_ch_children, efa_vt_children), 
                 facet_order_vars = c("age_group", "country", "fnum"),
                 facet_lab_split = T) +
  theme(panel.spacing.x = unit(c(rep(0.2, 4), 1, rep(0.2, 4)), "line"),
        legend.position = "bottom") +
  guides(fill = guide_colorbar(barwidth = 30, barheight = 0.5, 
                               title = "Factor loading", title.vjust = 1))

ggsave("../figures/fig01v1_orthogonal.png")
# FIGURE 1, version 2 (included in main text)
loadings_adults %>%
  bind_rows(loadings_children) %>%
  # select(-contains("_ord")) %>%
  mutate(factor_bhm = case_when(
    grepl("body", tolower(factor_descript)) ~ "BODY-like factors",
    grepl("mind", tolower(factor_descript)) ~ "MIND-like factors",
    grepl("heart", tolower(factor_descript)) ~ "HEART-like factors",
    TRUE ~ "Other")) %>%
  left_join(strong_noncross_load_all %>% 
              select(factor, capacity, strong_load, cross_load)) %>%
  mutate(font_face = case_when(
    strong_load == 1 & is.na(cross_load) ~ "bold",
    TRUE ~ "plain")) %>%
  ggplot(aes(x = reorder(paste(gsub("Factor ", "F", factor_name), 
                               factor_descript, sep = ": "), 
                         as.numeric(country)), 
             y = reorder(capacity_ord_us, desc(capacity_ord_us)),
             fill = loading)) +
  facet_grid(cols = vars(factor_bhm, age_group), 
             scales = "free", space = "free") +
  geom_tile(color = "black", size = 0.2) +
  geom_text(aes(label = format(round(loading, 2), nsmall = 2), 
                fontface = font_face), size = 3) +
  scale_fill_distiller(palette = "RdYlBu", limits = c(-1, 1)) +
  theme_minimal() +
  labs(x = NULL, y = NULL) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
        panel.spacing.x = unit(c(0.2, 1, 0.2, 1, 0.2, 1, 0.2), "line"),
        legend.position = "bottom") +
  guides(fill = guide_colorbar(barwidth = 30, barheight = 0.5, 
                               title = "Factor loading", title.vjust = 1))

  # select(country, capacity, loading) %>%
  # mutate(loading = round(loading, 2)) %>%
  # spread(country, loading)
ggsave("../figures/fig01v2_orthogonal.png")

Variance accounted for

Vaccounted_fun <- function(efa_name) {
  country <- gsub("efa_", "", efa_name)
  country <- gsub("_.*$", "", country)
  age_group <- case_when(grepl("adult", efa_name) ~ "adults",
                         grepl("child", efa_name) ~ "children",
                         TRUE ~ NA_character_)
  
  efa <- get(efa_name)
  res <- efa$Vaccounted %>%
    data.frame() %>%
    rownames_to_column("metric") %>%
    mutate(country = factor(country, 
                            levels = c("us", "gh", "th", "ch", "vt"),
                            labels = levels_country),
           age_group = factor(age_group, levels = c("adults", "children")))
  
  return(res)
}
Vaccounted_all <- Vaccounted_fun("efa_us_adults") %>%
  full_join(Vaccounted_fun("efa_gh_adults")) %>%
  full_join(Vaccounted_fun("efa_th_adults")) %>%
  full_join(Vaccounted_fun("efa_ch_adults")) %>%
  full_join(Vaccounted_fun("efa_vt_adults")) %>%
  full_join(Vaccounted_fun("efa_us_children")) %>%
  full_join(Vaccounted_fun("efa_gh_children")) %>%
  full_join(Vaccounted_fun("efa_th_children")) %>%
  full_join(Vaccounted_fun("efa_ch_children")) %>%
  full_join(Vaccounted_fun("efa_vt_children"))
Vaccounted_all %>%
  filter(metric %in% c("Proportion Var", "Proportion Explained")) %>%
  gather(factor, value, starts_with("F")) %>%
  mutate(value = round(value, 2)) %>%
  spread(country, value) %>%
  arrange(age_group, factor, metric)
Vaccounted_all %>%
  filter(metric == "Cumulative Var") %>%
  gather(factor, value, starts_with("F")) %>%
  group_by(country, age_group) %>%
  top_n(1, value) %>%
  ungroup() %>%
  mutate(value = round(value, 2)) %>%
  select(metric, country, age_group, value) %>%
  spread(country, value) %>%
  arrange(age_group, metric)
LS0tCnRpdGxlOiAiQ29uY2VwdHMgb2YgbWVudGFsIGxpZmUgYWNyb3NzIGN1bHR1cmVzOiBTZWNvbmRhcnkgYW5hbHlzaXMiCnN1YnRpdGxlOiAiRXhwbG9yYXRvcnkgZmFjdG9yIGFuYWx5c2lzIHVzaW5nIGZ1bGwgZGF0YXNldHMsIFBlYXJzb24gY29ycmVsYXRpb25zLCBhbmQgb3J0aG9nb25hbCByb3RhdGlvbnMiCmF1dGhvcnM6ICJXZWlzbWFuLCBMZWdhcmUsICYgTHVocm1hbm4iCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKYGBge3Igc2V0dXB9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRiwgd2FybmluZyA9IEZBTFNFKQpgYGAKCkluIHRoaXMgbm90ZWJvb2sgd2UgY29uZHVjdCBleHBsb3JhdG9yeSBmYWN0b3IgYW5hbHlzZXMgKEVGQXMpIG9uIHRoZSBkYXRhc2V0cyBmb3Igb3VyIHN0dWRpZXMgb2YgY29uY2VwdHMgb2YgbWVudGFsIGxpZmUsIGluIHdoaWNoIGVhY2ggcGFydGljaXBhbnRzIGp1ZGdlZCB0aGUgdmFyaW91cyBtZW50YWwgY2FwYWNpdGllcyBvZiBhIHBhcnRpY3VsYXIgdGFyZ2V0IGVudGl0eS4gV2UgYW5hbHl6ZSBkYXRhc2V0cyBmb3IgYWR1bHRzIGFuZCBjaGlsZHJlbiBmcm9tIGVhY2ggb2Ygb3VyIGZpdmUgZmllbGQgc2l0ZXM6IHRoZSBVUywgR2hhbmEsIFRoYWlsYW5kLCBDaGluYSwgYW5kIFZhbnVhdHUuIAoKVGhpcyBub3RlYm9vayBjb250YWlucyBzZWNvbmRhcnkgYW5hbHlzZXMsIHBhcmFsbGVsIHRvIHRoZSByZXN1bHRzIHByZXNlbnRlZCBpbiB0aGUgbWFpbiB0ZXh0LCBpbiB3aGljaCB3ZSBwcmVzZW50IG9ydGhvZ29uYWwgcm90YXRpb25zIHJhdGhlciB0aGFuIG9ibGlxdWUgdHJhbnNmb3JtYXRpb25zIG9mIHRoZSBFRkEgcmVzdWx0cy4KCgpgYGB7ciwgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQpzb3VyY2UoIi4vc2NyaXB0cy9kZXBlbmRlbmNpZXMuUiIpCnNvdXJjZSgiLi9zY3JpcHRzL2N1c3RvbV9mdW5zLlIiKQpzb3VyY2UoIi4vc2NyaXB0cy92YXJfcmVjb2RlX2NvbnRyYXN0LlIiKQpgYGAKCmBgYHtyIGRhdGF9CiMgcmVhZCBpbiBkYXRhLCBzaG9ydGVuICJmZWVsIHNpY2ssIiBhbmQgbGltaXQgdG8gdW5pdmVyc2FsIHRhcmdldHMgYW5kIHF1ZXN0aW9uczogYWR1bHRzCmRfdXNfYWR1bHRzIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2RfdXNfYWR1bHRzLmNzdiIpICU+JQogIGZpbHRlcih0YXJnZXQgJWluJSBsZXZlbHNfdGFyZ2V0X3VuaXYsIHF1ZXN0aW9uX2NhdCA9PSAidW5pdmVyc2FsIikgJT4lCiAgbXV0YXRlKHF1ZXN0aW9uID0gZ3N1YigiXFwsIC4qJCIsICIgXFxbLi4uXFxdIiwgcXVlc3Rpb24pKQpkX2doX2FkdWx0cyA8LSByZWFkX2NzdigiLi4vZGF0YS9kX2doX2FkdWx0cy5jc3YiKSAlPiUKICBmaWx0ZXIodGFyZ2V0ICVpbiUgbGV2ZWxzX3RhcmdldF91bml2LCBxdWVzdGlvbl9jYXQgPT0gInVuaXZlcnNhbCIpICU+JQogIG11dGF0ZShxdWVzdGlvbiA9IGdzdWIoIlxcLCAuKiQiLCAiIFxcWy4uLlxcXSIsIHF1ZXN0aW9uKSkKZF90aF9hZHVsdHMgPC0gcmVhZF9jc3YoIi4uL2RhdGEvZF90aF9hZHVsdHMuY3N2IikgJT4lCiAgZmlsdGVyKHRhcmdldCAlaW4lIGxldmVsc190YXJnZXRfdW5pdiwgcXVlc3Rpb25fY2F0ID09ICJ1bml2ZXJzYWwiKSAlPiUKICBtdXRhdGUocXVlc3Rpb24gPSBnc3ViKCJcXCwgLiokIiwgIiBcXFsuLi5cXF0iLCBxdWVzdGlvbikpCmRfY2hfYWR1bHRzIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2RfY2hfYWR1bHRzLmNzdiIpICU+JQogIGZpbHRlcih0YXJnZXQgJWluJSBsZXZlbHNfdGFyZ2V0X3VuaXYsIHF1ZXN0aW9uX2NhdCA9PSAidW5pdmVyc2FsIikgJT4lCiAgbXV0YXRlKHF1ZXN0aW9uID0gZ3N1YigiXFwsIC4qJCIsICIgXFxbLi4uXFxdIiwgcXVlc3Rpb24pKQpkX3Z0X2FkdWx0cyA8LSByZWFkX2NzdigiLi4vZGF0YS9kX3Z0X2FkdWx0cy5jc3YiKSAlPiUKICBmaWx0ZXIodGFyZ2V0ICVpbiUgbGV2ZWxzX3RhcmdldF91bml2LCBxdWVzdGlvbl9jYXQgPT0gInVuaXZlcnNhbCIpICU+JQogIG11dGF0ZShxdWVzdGlvbiA9IGdzdWIoIlxcLCAuKiQiLCAiIFxcWy4uLlxcXSIsIHF1ZXN0aW9uKSkKCiMgcmVhZCBpbiBkYXRhLCBzaG9ydGVuICJmZWVsIHNpY2ssIiBhbmQgbGltaXQgdG8gdW5pdmVyc2FsIHRhcmdldHMgYW5kIHF1ZXN0aW9uczogY2hpbGRyZW4KZF91c19jaGlsZHJlbiA8LSByZWFkX2NzdigiLi4vZGF0YS9kX3VzX2NoaWxkcmVuLmNzdiIpICU+JQogIGZpbHRlcih0YXJnZXQgJWluJSBsZXZlbHNfdGFyZ2V0X3VuaXYsIHF1ZXN0aW9uX2NhdCA9PSAidW5pdmVyc2FsIikgJT4lCiAgbXV0YXRlKHF1ZXN0aW9uID0gZ3N1YigiXFwsIC4qJCIsICIgXFxbLi4uXFxdIiwgcXVlc3Rpb24pKQpkX2doX2NoaWxkcmVuIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2RfZ2hfY2hpbGRyZW4uY3N2IikgJT4lCiAgZmlsdGVyKHRhcmdldCAlaW4lIGxldmVsc190YXJnZXRfdW5pdiwgcXVlc3Rpb25fY2F0ID09ICJ1bml2ZXJzYWwiKSAlPiUKICBtdXRhdGUocXVlc3Rpb24gPSBnc3ViKCJcXCwgLiokIiwgIiBcXFsuLi5cXF0iLCBxdWVzdGlvbikpCmRfdGhfY2hpbGRyZW4gPC0gcmVhZF9jc3YoIi4uL2RhdGEvZF90aF9jaGlsZHJlbi5jc3YiKSAlPiUKICBmaWx0ZXIodGFyZ2V0ICVpbiUgbGV2ZWxzX3RhcmdldF91bml2LCBxdWVzdGlvbl9jYXQgPT0gInVuaXZlcnNhbCIpICU+JQogIG11dGF0ZShxdWVzdGlvbiA9IGdzdWIoIlxcLCAuKiQiLCAiIFxcWy4uLlxcXSIsIHF1ZXN0aW9uKSkKZF9jaF9jaGlsZHJlbiA8LSByZWFkX2NzdigiLi4vZGF0YS9kX2NoX2NoaWxkcmVuLmNzdiIpICU+JQogIGZpbHRlcih0YXJnZXQgJWluJSBsZXZlbHNfdGFyZ2V0X3VuaXYsIHF1ZXN0aW9uX2NhdCA9PSAidW5pdmVyc2FsIikgJT4lCiAgbXV0YXRlKHF1ZXN0aW9uID0gZ3N1YigiXFwsIC4qJCIsICIgXFxbLi4uXFxdIiwgcXVlc3Rpb24pKQpkX3Z0X2NoaWxkcmVuIDwtIHJlYWRfY3N2KCIuLi9kYXRhL2RfdnRfY2hpbGRyZW4uY3N2IikgJT4lCiAgZmlsdGVyKHRhcmdldCAlaW4lIGxldmVsc190YXJnZXRfdW5pdiwgcXVlc3Rpb25fY2F0ID09ICJ1bml2ZXJzYWwiKSAlPiUKICBtdXRhdGUocXVlc3Rpb24gPSBnc3ViKCJcXCwgLiokIiwgIiBcXFsuLi5cXF0iLCBxdWVzdGlvbikpICU+JQogICMgZmlsdGVyIG91dCBwYXJ0aWNpcGFudHMgb3V0c2lkZSBvZiB0aGUgYWdlIHJhbmdlCiAgZmlsdGVyKChhZ2UgPj0gNiAmIGFnZSA8PSAxMikgfCBpcy5uYShhZ2UpKQpgYGAKCmBgYHtyIHdpZGV9CiMgbWFrZSB3aWRlLWZvcm0gZGF0YXNldHMgZm9yIEVGQTogYWR1bHRzCmRfdXNfYWR1bHRzX3cgPC0gd2lkZV9kZl9mdW4oZF91c19hZHVsdHMpCmRfZ2hfYWR1bHRzX3cgPC0gd2lkZV9kZl9mdW4oZF9naF9hZHVsdHMpCmRfdGhfYWR1bHRzX3cgPC0gd2lkZV9kZl9mdW4oZF90aF9hZHVsdHMpCmRfY2hfYWR1bHRzX3cgPC0gd2lkZV9kZl9mdW4oZF9jaF9hZHVsdHMpCmRfdnRfYWR1bHRzX3cgPC0gd2lkZV9kZl9mdW4oZF92dF9hZHVsdHMpCgojIG1ha2Ugd2lkZS1mb3JtIGRhdGFzZXRzIGZvciBFRkE6IGNoaWxkcmVuCmRfdXNfY2hpbGRyZW5fdyA8LSB3aWRlX2RmX2Z1bihkX3VzX2NoaWxkcmVuKQpkX2doX2NoaWxkcmVuX3cgPC0gd2lkZV9kZl9mdW4oZF9naF9jaGlsZHJlbikKIyBkX2doX2VuZ19jaGlsZHJlbl93IDwtIHdpZGVfZGZfZnVuKGRfZ2hfZW5nX2NoaWxkcmVuKQpkX3RoX2NoaWxkcmVuX3cgPC0gd2lkZV9kZl9mdW4oZF90aF9jaGlsZHJlbikKZF9jaF9jaGlsZHJlbl93IDwtIHdpZGVfZGZfZnVuKGRfY2hfY2hpbGRyZW4pCmRfdnRfY2hpbGRyZW5fdyA8LSB3aWRlX2RmX2Z1bihkX3Z0X2NoaWxkcmVuKQpgYGAKCgojIEFkdWx0cwoKIyMgU2FtcGxlcwoKYGBge3Igc2FtcGxlcyBhZHVsdHN9CmJpbmRfcm93cyhkX3VzX2FkdWx0cywgZF9naF9hZHVsdHMsIGRfdGhfYWR1bHRzLCBkX2NoX2FkdWx0cywgZF92dF9hZHVsdHMpICU+JQogIG11dGF0ZShjb3VudHJ5ID0gZmFjdG9yKGNvdW50cnksIGxldmVscyA9IGxldmVsc19jb3VudHJ5KSkgJT4lCiAgZGlzdGluY3QoY291bnRyeSwgc3Vial9pZCkgJT4lCiAgY291bnQoY291bnRyeSkgJT4lCiAgamFuaXRvcjo6YWRvcm5fdG90YWxzKCkKYGBgCgojIyBTY2FsZSB1c2UKCmBgYHtyIHNjYWxlIHVzZSBtZWFuIG92ZXJhbGwgYWR1bHRzfQpiaW5kX3Jvd3MoZF91c19hZHVsdHMsIGRfZ2hfYWR1bHRzLCBkX3RoX2FkdWx0cywgZF9jaF9hZHVsdHMsIGRfdnRfYWR1bHRzKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBsZXZlbHNfY291bnRyeSksCiAgICAgICAgIHJlc3BvbnNlX2NhdCA9IHJlY29kZV9mYWN0b3IocmVzcG9uc2VfY2F0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJubyIgPSAibm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJraW5kIG9mIiA9ICJraW5kIG9mIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAieWVzIiA9ICJ5ZXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWlzc2luZyA9ICJtaXNzaW5nIGRhdGEiKSkgJT4lCiAgY291bnQoY291bnRyeSwgcmVzcG9uc2VfY2F0KSAlPiUKICBjb21wbGV0ZShyZXNwb25zZV9jYXQsIG5lc3RpbmcoY291bnRyeSksIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgbXV0YXRlKHByb3AgPSBuL3N1bShuLCBuYS5ybSA9IFQpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1uKSAlPiUKICBzcHJlYWQocmVzcG9uc2VfY2F0LCBwcm9wKSAlPiUKICBqYW5pdG9yOjphZG9ybl9wY3RfZm9ybWF0dGluZyhkaWdpdHMgPSAyKQpgYGAKCiMjIEZhY3RvciByZXRlbnRpb246IHBhcmFsbGVsIGFuYWx5c2lzCgpgYGB7ciBwYXJhbGxlbCBkaXN0IGFkdWx0cywgZmlnLndpZHRoID0gMywgZmlnLmFzcCA9IDAuNX0KIyBOT1RFOiBIZXJlIGlzIGRpc3RyaWJ1dGlvbiBvdmVyIG91dGNvbWVzIG9mIHBhcmFsbGVsIGFuYWx5c2lzIHdpdGggMTAwIGl0ZXJhdGlvbnMuIFdlJ2xsIGNob29zZSB0aGUgbWVkaWFuIG51bWJlciBvZiBmYWN0b3JzLgoKaWYgKGZpbGUuZXhpc3RzKCIuLi9yZXN1bHRzL3BhX291dGNvbWVzX2Rpc3RfYWR1bHRzLlJEUyIpKSB7CiAgCiAgcGFfb3V0Y29tZXNfZGlzdF9hZHVsdHMgPC0gcmVhZFJEUygiLi4vcmVzdWx0cy9wYV9vdXRjb21lc19kaXN0X2FkdWx0cy5SRFMiKQogIAp9IGVsc2UgewogIAogIHBhX291dGNvbWVzX2Rpc3RfYWR1bHRzIDwtIGRhdGEuZnJhbWUodXMgPSBOVUxMLCBnaCA9IE5VTEwsIHRoID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoID0gTlVMTCwgdnQgPSBOVUxMKQogIAogIHNldC5zZWVkKDU0MzIxKQogIG5fY29yZXMgPC0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkKICBvcHRpb25zKG1jLmNvcmVzID0gbl9jb3JlcykKICAKICBmb3IgKGkgaW4gMToxMDApIHsKICAgIHBhX291dGNvbWVzX2Rpc3RfYWR1bHRzW2ksICJ1cyJdIDwtIGZhLnBhcmFsbGVsKGRfdXNfYWR1bHRzX3csIHBsb3QgPSBGKSRuZmFjdAogICAgcGFfb3V0Y29tZXNfZGlzdF9hZHVsdHNbaSwgImdoIl0gPC0gZmEucGFyYWxsZWwoZF9naF9hZHVsdHNfdywgcGxvdCA9IEYpJG5mYWN0ICAgICAKICAgIHBhX291dGNvbWVzX2Rpc3RfYWR1bHRzW2ksICJ0aCJdIDwtIGZhLnBhcmFsbGVsKGRfdGhfYWR1bHRzX3csIHBsb3QgPSBGKSRuZmFjdAogICAgcGFfb3V0Y29tZXNfZGlzdF9hZHVsdHNbaSwgImNoIl0gPC0gZmEucGFyYWxsZWwoZF9jaF9hZHVsdHNfdywgcGxvdCA9IEYpJG5mYWN0CiAgICBwYV9vdXRjb21lc19kaXN0X2FkdWx0c1tpLCAidnQiXSA8LSBmYS5wYXJhbGxlbChkX3Z0X2FkdWx0c193LCBwbG90ID0gRikkbmZhY3QKICB9CiAgCiAgc2F2ZVJEUyhwYV9vdXRjb21lc19kaXN0X2FkdWx0cywgZmlsZSA9ICIuLi9yZXN1bHRzL3BhX291dGNvbWVzX2Rpc3RfYWR1bHRzLlJEUyIpCn0KCiMgcGxvdApwYV9vdXRjb21lc19kaXN0X2FkdWx0cyAlPiUKICByb3duYW1lc190b19jb2x1bW4oIml0ZXIiKSAlPiUKICBnYXRoZXIoY291bnRyeSwgbmZhY3QsIC1pdGVyKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LAogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInVzIiwgImdoIiwgInRoIiwgImNoIiwgInZ0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gbGV2ZWxzX2NvdW50cnkpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuZmFjdCkpICsKICBmYWNldF9ncmlkKH4gY291bnRyeSkgKwogIGdlb21fYmFyKHN0YXQgPSAiY291bnQiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMSwgbWF4KHBhX291dGNvbWVzX2Rpc3RfYWR1bHRzKSArIDEpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAwLCAxKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgZmFjdG9ycyBzdWdnZXN0ZWQgYnkgZmEucGFyYWxsZWwoKSIpCmBgYAoKIyMgRXhwbG9yYXRvcnkgZmFjdG9yIGFuYWx5c2lzCgpgYGB7ciBlZmEgYWR1bHRzfQpzZXQuc2VlZCg1NDMyMSkKCiMgZG8gZXhwbG9yYXRvcnkgZmFjdG9yIGFuYWx5c2lzOiBhZHVsdHMKZWZhX3VzX2FkdWx0cyA8LSBmYV9mdW4oZF91c19hZHVsdHNfdywKICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2FkdWx0cyR1cyksCiAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfdXNfYWR1bHRzJGxvYWRpbmdzKSA8LSBwYXN0ZTAoInVzQURVTFRTXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX3VzX2FkdWx0cyRsb2FkaW5ncykpCgplZmFfZ2hfYWR1bHRzIDwtIGZhX2Z1bihkX2doX2FkdWx0c193LCAKICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2FkdWx0cyRnaCksCiAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfZ2hfYWR1bHRzJGxvYWRpbmdzKSA8LSBwYXN0ZTAoImdoQURVTFRTXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX2doX2FkdWx0cyRsb2FkaW5ncykpCgplZmFfdGhfYWR1bHRzIDwtIGZhX2Z1bihkX3RoX2FkdWx0c193LCAKICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2FkdWx0cyR0aCksCiAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfdGhfYWR1bHRzJGxvYWRpbmdzKSA8LSBwYXN0ZTAoInRoQURVTFRTXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX3RoX2FkdWx0cyRsb2FkaW5ncykpCgplZmFfY2hfYWR1bHRzIDwtIGZhX2Z1bihkX2NoX2FkdWx0c193LCAKICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2FkdWx0cyRjaCksCiAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfY2hfYWR1bHRzJGxvYWRpbmdzKSA8LSBwYXN0ZTAoImNoQURVTFRTXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX2NoX2FkdWx0cyRsb2FkaW5ncykpCgplZmFfdnRfYWR1bHRzIDwtIGZhX2Z1bihkX3Z0X2FkdWx0c193LCAKICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2FkdWx0cyR2dCksCiAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfdnRfYWR1bHRzJGxvYWRpbmdzKSA8LSBwYXN0ZTAoInZ0QURVTFRTXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX3Z0X2FkdWx0cyRsb2FkaW5ncykpCmBgYAoKYGBge3IgZmFjdG9yIG5hbWVzIGFkdWx0c30KZmFjdG9yX25hbWVzX2FkdWx0cyA8LSBkYXRhLmZyYW1lKGZhY3RvciA9IGMoY29sbmFtZXMoZWZhX3VzX2FkdWx0cyRsb2FkaW5ncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKGVmYV9naF9hZHVsdHMkbG9hZGluZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhlZmFfdGhfYWR1bHRzJGxvYWRpbmdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX2NoX2FkdWx0cyRsb2FkaW5ncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKGVmYV92dF9hZHVsdHMkbG9hZGluZ3MpKSkgJT4lCiAgbXV0YXRlKGFnZV9ncm91cCA9ICJhZHVsdHMiKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGNhc2Vfd2hlbihncmVwbCgiXnVzIiwgZmFjdG9yKSB+ICJVUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl5naCIsIGZhY3RvcikgfiAiR2hhbmEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJedGgiLCBmYWN0b3IpIH4gIlRoYWlsYW5kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiXmNoIiwgZmFjdG9yKSB+ICJDaGluYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl52dCIsIGZhY3RvcikgfiAiVmFudWF0dSIpLAogICAgICAgICBjb3VudHJ5ID0gZmFjdG9yKGNvdW50cnksIGxldmVsc19jb3VudHJ5KSkgJT4lCiAgbXV0YXRlKGZhY3Rvcl9uYW1lID0gZ3N1YigiXnVzIiwgIlVTICIsIGZhY3RvciksCiAgICAgICAgIGZhY3Rvcl9uYW1lID0gZ3N1YigiXmdoIiwgIkdoLiAiLCBmYWN0b3JfbmFtZSksCiAgICAgICAgIGZhY3Rvcl9uYW1lID0gZ3N1YigiXnRoIiwgIlRoLiAiLCBmYWN0b3JfbmFtZSksCiAgICAgICAgIGZhY3Rvcl9uYW1lID0gZ3N1YigiXmNoIiwgIkNoLiAiLCBmYWN0b3JfbmFtZSksCiAgICAgICAgIGZhY3Rvcl9uYW1lID0gZ3N1YigiXnZ0IiwgIlZhLiAiLCBmYWN0b3JfbmFtZSksCiAgICAgICAgIGZhY3Rvcl9uYW1lID0gZ3N1YigiQURVTFRTIiwgImFkdWx0cyIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJfRiIsICIgRmFjdG9yICIsIGZhY3Rvcl9uYW1lKSkgJT4lCiAgbXV0YXRlKGZhY3Rvcl9kZXNjcmlwdCA9IHJlY29kZShmYWN0b3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c0FEVUxUU19GMSA9ICJCb2R5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzQURVTFRTX0YyID0gIkhlYXJ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVzQURVTFRTX0YzID0gIk1pbmQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2hBRFVMVFNfRjEgPSAiSW5uZXIgc3BoZXJlIChtaW5kLWxpa2UpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdoQURVTFRTX0YyID0gIkJvZHktbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaEFEVUxUU19GMyA9ICJJbnRlcnBlcnNvbmFsLCByZWxpZ2lvdXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhBRFVMVFNfRjEgPSAiQm9keS1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoQURVTFRTX0YyID0gIkhlYXJ0LWxpa2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhBRFVMVFNfRjMgPSAiTWluZC1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoQURVTFRTX0YxID0gIkhlYXJ0LWxpa2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hBRFVMVFNfRjIgPSAiQm9keS1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoQURVTFRTX0YzID0gIk1pbmQtbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2dEFEVUxUU19GMSA9ICJIYXJtb255IChtaW5kLWxpa2UsIGhlYXJ0LWxpa2UpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZ0QURVTFRTX0YyID0gIlNpbiAoYm9keS1saWtlKSIpLAogICAgICAgICBmYWN0b3JfbGFiZGVzY3JpcHQgPSBwYXN0ZShnc3ViKCIuKl9GIiwgIkYiLCBmYWN0b3IpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JfZGVzY3JpcHQsIHNlcCA9ICI6ICIpKQpgYGAKCiMjIEZhY3RvciBsb2FkaW5ncwoKYGBge3Igb3JkZXIgYWR1bHRzfQojIG9yZGVyIGNhcGFjaXRpZXM6IGFkdWx0cwpvcmRlcl91c19hZHVsdHMgPC0gZmEuc29ydChlZmFfdXNfYWR1bHRzKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX2doX2FkdWx0cyA8LSBmYS5zb3J0KGVmYV9naF9hZHVsdHMpJGxvYWRpbmdzW10gJT4lIHJvd25hbWVzKCkKb3JkZXJfdGhfYWR1bHRzIDwtIGZhLnNvcnQoZWZhX3RoX2FkdWx0cykkbG9hZGluZ3NbXSAlPiUgcm93bmFtZXMoKQpvcmRlcl9jaF9hZHVsdHMgPC0gZmEuc29ydChlZmFfY2hfYWR1bHRzKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX3Z0X2FkdWx0cyA8LSBmYS5zb3J0KGVmYV92dF9hZHVsdHMpJGxvYWRpbmdzW10gJT4lIHJvd25hbWVzKCkKYGBgCgpgYGB7ciBsb2FkaW5ncyBhZHVsdHN9CiMgY29tcGlsZSBsb2FkaW5nczogYWR1bHRzCmxvYWRpbmdzX2FkdWx0cyA8LSBiaW5kX3Jvd3MoCiAgbG9hZGluZ3NfZnVuKGVmYV91c19hZHVsdHMpICU+JSBtdXRhdGUoY291bnRyeSA9ICJVUyIpLAogIGxvYWRpbmdzX2Z1bihlZmFfZ2hfYWR1bHRzKSAlPiUgbXV0YXRlKGNvdW50cnkgPSAiR2hhbmEiKSwKICBsb2FkaW5nc19mdW4oZWZhX3RoX2FkdWx0cykgJT4lIG11dGF0ZShjb3VudHJ5ID0gIlRoYWlsYW5kIiksCiAgbG9hZGluZ3NfZnVuKGVmYV9jaF9hZHVsdHMpICU+JSBtdXRhdGUoY291bnRyeSA9ICJDaGluYSIpLAogIGxvYWRpbmdzX2Z1bihlZmFfdnRfYWR1bHRzKSAlPiUgbXV0YXRlKGNvdW50cnkgPSAiVmFudWF0dSIpKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBsZXZlbHNfY291bnRyeSksCiAgICAgICAgIGNhcGFjaXR5X29yZF91cyA9IGZhY3RvcihjYXBhY2l0eSwgbGV2ZWxzID0gb3JkZXJfdXNfYWR1bHRzKSwKICAgICAgICAgY2FwYWNpdHlfb3JkX2doID0gZmFjdG9yKGNhcGFjaXR5LCBsZXZlbHMgPSBvcmRlcl9naF9hZHVsdHMpLAogICAgICAgICBjYXBhY2l0eV9vcmRfdGggPSBmYWN0b3IoY2FwYWNpdHksIGxldmVscyA9IG9yZGVyX3RoX2FkdWx0cyksCiAgICAgICAgIGNhcGFjaXR5X29yZF9jaCA9IGZhY3RvcihjYXBhY2l0eSwgbGV2ZWxzID0gb3JkZXJfY2hfYWR1bHRzKSwKICAgICAgICAgY2FwYWNpdHlfb3JkX3Z0ID0gZmFjdG9yKGNhcGFjaXR5LCBsZXZlbHMgPSBvcmRlcl92dF9hZHVsdHMpKSAlPiUKICBhcnJhbmdlKGNvdW50cnksIGZhY3RvciwgZGVzYyhhYnMobG9hZGluZykpLCBjYXBhY2l0eSkgJT4lCiAgbXV0YXRlKG9yZGVyID0gMTpucm93KC4pKSAlPiUKICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2FkdWx0cykKYGBgCgpgYGB7ciBoZWF0bWFwIGFkdWx0cywgZmlnLndpZHRoID0gNSwgZmlnLmFzcCA9IDAuN30KIyBtYWtlIGhlYXRtYXAgZmlndXJlOiBhZHVsdHMKbG9hZGluZ3NfYWR1bHRzICU+JQogIG11dGF0ZShmYWN0b3JfbnVtID0gYXMubnVtZXJpYyhnc3ViKCIuKkYiLCAiIiwgZmFjdG9yKSkpICU+JQogIG11dGF0ZShzYW1wbGUgPSBwYXN0ZShjb3VudHJ5LCAiYWR1bHRzIiwgc2VwID0gIlxuIikpICU+JQogIGxlZnRfam9pbihmYWN0b3JfbmFtZXNfYWR1bHRzKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBsZXZlbHNfY291bnRyeSkpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZmFjdG9yX2xhYmRlc2NyaXB0LCBmYWN0b3JfbnVtKSwgCiAgICAgICAgICAgICB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfdXMpKSwKICAgICAgICAgICAgICMgeSA9IHJlb3JkZXIoY2FwYWNpdHksIGRlc2MoY2FwYWNpdHlfb3JkX2VjKSksIAogICAgICAgICAgICAgIyB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfZ2gpKSwKICAgICAgICAgICAgICMgeSA9IHJlb3JkZXIoY2FwYWNpdHksIGRlc2MoY2FwYWNpdHlfb3JkX3RoKSksCiAgICAgICAgICAgICAjIHkgPSByZW9yZGVyKGNhcGFjaXR5LCBkZXNjKGNhcGFjaXR5X29yZF9jaCkpLAogICAgICAgICAgICAgIyB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfdnQpKSwKICAgICAgICAgICAgIGZpbGwgPSBsb2FkaW5nKSkgKwogIGZhY2V0X2dyaWQofiByZW9yZGVyKHNhbXBsZSwgYXMubnVtZXJpYyhjb3VudHJ5KSksIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdChyb3VuZChsb2FkaW5nLCAyKSwgbnNtYWxsID0gMikpLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiUmRZbEJ1IiwgbGltaXRzID0gYygtMSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihiYXJoZWlnaHQgPSAyMCwgYmFyd2lkdGggPSAwLjUpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSksCiAgICAgICAgcGFuZWwuc3BhY2luZy54ID0gdW5pdCgwLjgsICJsaW5lcyIpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJDYXBhY2l0eSIsIGZpbGwgPSAiRmFjdG9yXG5sb2FkaW5nIikKYGBgCgojIyBDb25ncnVlbmNlCgpgYGB7ciBjb25ncnVlbmNlIGFkdWx0c30KY29uZ19hZHVsdHMgPC0gZmEuY29uZ3J1ZW5jZSh4ID0gbGlzdChlZmFfdXNfYWR1bHRzJGxvYWRpbmdzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmYV9naF9hZHVsdHMkbG9hZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZhX3RoX2FkdWx0cyRsb2FkaW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmFfY2hfYWR1bHRzJGxvYWRpbmdzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmYV92dF9hZHVsdHMkbG9hZGluZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDUpICU+JQogICMgZ2V0X3VwcGVyX3RyaV9mdW4oKSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJmYWN0b3JfQSIpICU+JQogIGdhdGhlcihmYWN0b3JfQiwgY29uZywgLWZhY3Rvcl9BKSAlPiUKICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2FkdWx0cyAlPiUgCiAgICAgICAgICAgICAgcmVuYW1lX2FsbChsaXN0KH4gKHBhc3RlKC4sICJBIiwgc2VwID0gIl8iKSkpKSkgJT4lCiAgbGVmdF9qb2luKGZhY3Rvcl9uYW1lc19hZHVsdHMgJT4lIAogICAgICAgICAgICAgIHJlbmFtZV9hbGwobGlzdCh+IChwYXN0ZSguLCAiQiIsIHNlcCA9ICJfIikpKSkpCmBgYAoKYGBge3IgdG9wIG1hdGNoIGFkdWx0c30KY29uZ19hZHVsdHNfdG9wX21hdGNoX0EgPC0gdG9wX21hdGNoX2Z1bihjb25nX2FkdWx0cywgImNvdW50cnlfQSIpCmNvbmdfYWR1bHRzX3RvcF9tYXRjaF9CIDwtIHRvcF9tYXRjaF9mdW4oY29uZ19hZHVsdHMsICJjb3VudHJ5X0IiKQpgYGAKCmBgYHtyIGNvbmcgYWxsIHBhaXJzIGFkdWx0cywgZmlnLndpZHRoID0gNSwgZmlnLmFzcCA9IDAuN30KY29uZ19hZHVsdHMgJT4lCiAgbXV0YXRlX2F0KCN2YXJzKGNvbnRhaW5zKCJsYWJkZXNjcmlwdCIpKSwKICAgIHZhcnMoZmFjdG9yX2xhYmRlc2NyaXB0X0EpLAogICAgZnVucyhnc3ViKCIgXFwoIiwgIlxuXFwoIiwgLikpKSAlPiUKICBtdXRhdGVfYXQoI3ZhcnMoY29udGFpbnMoImxhYmRlc2NyaXB0IikpLAogICAgdmFycyhmYWN0b3JfbGFiZGVzY3JpcHRfQSksCiAgICBmdW5zKGdzdWIoIlxcLyIsICJcXC9cbiIsIC4pKSkgJT4lCiAgIyBsZWZ0X2pvaW4oY29uZ19hZHVsdHNfdG9wX21hdGNoX0EgJT4lIHJlbmFtZSh0b3BfbWF0Y2hfQSA9IHRvcF9tYXRjaCkpICU+JQogIGxlZnRfam9pbihjb25nX2FkdWx0c190b3BfbWF0Y2hfQiAlPiUgcmVuYW1lKHRvcF9tYXRjaF9CID0gdG9wX21hdGNoKSkgJT4lCiAgbXV0YXRlKGlzX3RvcF9tYXRjaCA9IGNhc2Vfd2hlbihmYWN0b3JfQSA9PSBmYWN0b3JfQiB+ICJib2xkLml0YWxpYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZhY3Rvcl9BID09IHRvcF9tYXRjaF9BIH4gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9yX0IgPT0gdG9wX21hdGNoX0IgfiAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gInBsYWluIikpICU+JQogICMgbXV0YXRlKGNvbmcgPSBpZmVsc2UoY29uZyA9PSAxLCBOQV9yZWFsXywgY29uZykpICU+JQogIG11dGF0ZShzYW1wbGVfQSA9IHBhc3RlKHRvdXBwZXIoY291bnRyeV9BKSwgImFkdWx0cyIsIHNlcCA9ICI6XG4iKSkgJT4lCiAgbXV0YXRlKHNhbXBsZV9CID0gcGFzdGUodG91cHBlcihjb3VudHJ5X0IpLCAiYWR1bHRzIiwgc2VwID0gIjpcbiIpKSAlPiUKICBtdXRhdGVfYXQodmFycyhjb3VudHJ5X0EsIGNvdW50cnlfQiksCiAgICAgICAgICAgIGZ1bnMoZmFjdG9yKHRvdXBwZXIoLiksIGxldmVscyA9IHRvdXBwZXIobGV2ZWxzX2NvdW50cnkpKSkpICU+JQogIGdncGxvdChhZXMoeCA9IGZhY3Rvcl9sYWJkZXNjcmlwdF9BLAogICAgICAgICAgICAgeSA9IHJlb3JkZXIoZmFjdG9yX2xhYmRlc2NyaXB0X0IsIGRlc2MoZmFjdG9yX2xhYmRlc2NyaXB0X0IpKSwKICAgICAgICAgICAgIGZpbGwgPSBjb25nKSkgKwogIGZhY2V0X2dyaWQocmVvcmRlcihzYW1wbGVfQiwgYXMubnVtZXJpYyhjb3VudHJ5X0IpKSB+IAogICAgICAgICAgICAgICByZW9yZGVyKHNhbXBsZV9BLCBhcy5udW1lcmljKGNvdW50cnlfQSkpLCAKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNhc2Vfd2hlbihpcy5uYShjb25nKSB+ICIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGZvcm1hdChyb3VuZChjb25nLCAyKSwgbnNtYWxsID0gMikpLAogICAgICAgICAgICAgICAgZm9udGZhY2UgPSBpc190b3BfbWF0Y2gsCiAgICAgICAgICAgICAgICBjb2xvciA9IGlzX3RvcF9tYXRjaCksCiAgICAgICAgICAgIHNpemUgPSAzLCBzaG93LmxlZ2VuZCA9IEYpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZGFya3JlZCIsICJkYXJrYmx1ZSIsICJibGFjayIpKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gInZpcmlkaXMiLCAKICAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2NvbG9yYmFyKGJhcndpZHRoID0gMjUsIGJhcmhlaWdodCA9IDAuNSkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIikpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgZmlsbCA9IGV4cHJlc3Npb24oaXRhbGljKHJbY10pKSkKYGBgCgojIyBCb290c3RyYXBwZWQgY29uZ3J1ZW5jZQoKYGBge3IgYm9vdHN0cmFwIGNvbmdydWVuY2UgYWR1bHRzfQppZiAoZmlsZS5leGlzdHMoIi4uL3Jlc3VsdHMvY29uZ19kZl9hZHVsdHNfb3J0aG9nb25hbC5SRFMiKSkgewogIAogIGNvbmdfZGZfYWR1bHRzIDwtIHJlYWRSRFMoIi4uL3Jlc3VsdHMvY29uZ19kZl9hZHVsdHNfb3J0aG9nb25hbC5SRFMiKQogIAp9IGVsc2UgewogIAogIGJzX2FkdWx0cyA8LSBsb2FkaW5nc19hZHVsdHMgJT4lCiAgICBzZWxlY3QoY2FwYWNpdHksIGZhY3RvciwgbG9hZGluZykgJT4lCiAgICBzcHJlYWQoZmFjdG9yLCBsb2FkaW5nKSAlPiUKICAgIHNlbGVjdCgtY2FwYWNpdHkpICU+JQogICAgc2pzdGF0czo6Ym9vdHN0cmFwKDEwMDApIAogIAogIGZhY3RvcnMgPC0gbGV2ZWxzKGZhY3Rvcihsb2FkaW5nc19hZHVsdHMkZmFjdG9yKSkKICAKICBjb25nX2RmX2FkdWx0cyA8LSBkYXRhLmZyYW1lKE5VTEwpCiAgZm9yIChpIGluIGZhY3RvcnMpIHsKICAgIGZvciAoaiBpbiBmYWN0b3JzKSB7CiAgICAgIGNuYW1lIDwtIHBhc3RlKGksIGosIHNlcCA9ICIuIikKICAgICAgdGVtcCA8LSBic19hZHVsdHMgJT4lCiAgICAgICAgbXV0YXRlKGNvbmcgPSBtYXBfZGJsKHN0cmFwLCB+bHNhOjpjb3NpbmUoYXMuZGF0YS5mcmFtZSgueClbLGldLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoLngpWyxqXSkpKQogICAgICBjb25nX2RmX2FkdWx0c1sxOjEwMDAsIGNuYW1lXSA8LSB0ZW1wJGNvbmcKICAgIH0KICB9CiAgCiAgY29uZ19kZl9hZHVsdHMgPC0gY29uZ19kZl9hZHVsdHMgJT4lCiAgICBnYXRoZXIoZmFjdG9yX3BhaXIsIGNvbmcpICU+JQogICAgc2VwYXJhdGUoZmFjdG9yX3BhaXIsIGludG8gPSBjKCJmYWN0b3JfQSIsICJmYWN0b3JfQiIpLCBzZXAgPSAiXFwuIikgJT4lCiAgICBncm91cF9ieShmYWN0b3JfQSwgZmFjdG9yX0IpICU+JQogICAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGNvbmcpLAogICAgICAgICAgICAgIGNpX2xvd2VyID0gY2lfbG93ZXIoY29uZyksCiAgICAgICAgICAgICAgY2lfdXBwZXIgPSBjaV91cHBlcihjb25nKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2FkdWx0cyAlPiUKICAgICAgICAgICAgICAgIHJlbmFtZV9hbGwoZnVucyhwYXN0ZSguLCAiQSIsIHNlcCA9ICJfIikpKSkgJT4lCiAgICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2FkdWx0cyAlPiUKICAgICAgICAgICAgICAgIHJlbmFtZV9hbGwoZnVucyhwYXN0ZSguLCAiQiIsIHNlcCA9ICJfIikpKSkKICAKICBybShpLCBqLCBjbmFtZSwgdGVtcCwgZmFjdG9ycykKICAKICBzYXZlUkRTKGNvbmdfZGZfYWR1bHRzLCBmaWxlID0gIi4uL3Jlc3VsdHMvY29uZ19kZl9hZHVsdHNfb3J0aG9nb25hbC5SRFMiKQp9CmBgYAoKYGBge3IgY29uZyBtaW4gYWR1bHRzfQojIGZpbmQgbWluaW11bSB2YWx1ZSB0byBzZXQgY29uc3RhbnQgbG93ZXIgYm91bmQgb2YgcGxvdHMKbWluX2NvbmdfYWR1bHRzIDwtIGNvbmdfZGZfYWR1bHRzICU+JQogIHN1bW1hcmlzZShtaW5fY29uZyA9IG1pbihjaV9sb3dlciwgbmEucm0gPSBUKSkKYGBgCgpgYGB7ciBjb25nIGNpcyB1cyBiYXNlIGFkdWx0cywgZmlnLndpZHRoID0gNCwgZmlnLmFzcCA9IDAuOX0KIyBGSUdVUkUgMwpjb25nX3Bsb3RfZnVuKGNvbmdfZGYgPSBjb25nX2RmX2FkdWx0cywgd2hpY2hfY291bnRyeSA9ICJVUyIpICsKICB5bGltKG1pbl9jb25nX2FkdWx0cyRtaW5fY29uZywgMSkgKwogICMgeWxpbShOQSwgMSkgKwogIGxhYnMoeCA9IE5VTEwpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWcwM19vcnRob2dvbmFsLnBuZyIpCmBgYAoKYGBge3IgY29uZyBjaXMgZ2ggYmFzZSBhZHVsdHMsIGZpZy53aWR0aCA9IDQsIGZpZy5hc3AgPSAwLjl9CiMgRklHVVJFIFMxCmNvbmdfcGxvdF9mdW4oY29uZ19kZiA9IGNvbmdfZGZfYWR1bHRzICU+JQogICAgICAgICAgICAgICAgbXV0YXRlX2F0KCN2YXJzKGNvbnRhaW5zKCJsYWJkZXNjcmlwdCIpKSwKICAgICAgICAgICAgICAgICAgdmFycyhmYWN0b3JfbGFiZGVzY3JpcHRfQSksCiAgICAgICAgICAgICAgICAgIGZ1bnMoZ3N1YigiIFxcKCIsICJcblxcKCIsIC4pKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGVfYXQoI3ZhcnMoY29udGFpbnMoImxhYmRlc2NyaXB0IikpLAogICAgICAgICAgICAgICAgICB2YXJzKGZhY3Rvcl9sYWJkZXNjcmlwdF9BKSwKICAgICAgICAgICAgICAgICAgZnVucyhnc3ViKCJcXC8iLCAiXFwvXG4iLCAuKSkpLCAKICAgICAgICAgICAgICB3aGljaF9jb3VudHJ5ID0gIkdoYW5hIikgKwogIHlsaW0obWluX2NvbmdfYWR1bHRzJG1pbl9jb25nLCAxKQpnZ3NhdmUoIi4uL2ZpZ3VyZXMvZmlnUzAxX29ydGhvZ29uYWwucG5nIikKYGBgCgpgYGB7ciBjb25nIGNpcyB0aCBiYXNlIGFkdWx0cywgZmlnLndpZHRoID0gNCwgZmlnLmFzcCA9IDAuOX0KIyBGSUdVUkUgUzIKY29uZ19wbG90X2Z1bihjb25nX2RmID0gY29uZ19kZl9hZHVsdHMsIAogICAgICAgICAgICAgIHdoaWNoX2NvdW50cnkgPSAiVGhhaWxhbmQiKSArCiAgeWxpbShtaW5fY29uZ19hZHVsdHMkbWluX2NvbmcsIDEpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWdTMDJfb3J0aG9nb25hbC5wbmciKQpgYGAKCmBgYHtyIGNvbmcgY2lzIGNoIGJhc2UgYWR1bHRzLCBmaWcud2lkdGggPSA0LCBmaWcuYXNwID0gMC45fQojIEZJR1VSRSBTMwpjb25nX3Bsb3RfZnVuKGNvbmdfZGYgPSBjb25nX2RmX2FkdWx0cywgCiAgICAgICAgICAgICAgd2hpY2hfY291bnRyeSA9ICJDaGluYSIpICsKICB5bGltKG1pbl9jb25nX2FkdWx0cyRtaW5fY29uZywgMSkKZ2dzYXZlKCIuLi9maWd1cmVzL2ZpZ1MwM19vcnRob2dvbmFsLnBuZyIpCmBgYAoKYGBge3IgY29uZyBjaXMgdnQgYmFzZSBhZHVsdHMsIGZpZy53aWR0aCA9IDQsIGZpZy5hc3AgPSAwLjl9CiMgRklHVVJFIFM0CmNvbmdfcGxvdF9mdW4oY29uZ19kZiA9IGNvbmdfZGZfYWR1bHRzICU+JQogICAgICAgICAgICAgICAgbXV0YXRlX2F0KCN2YXJzKGNvbnRhaW5zKCJsYWJkZXNjcmlwdCIpKSwKICAgICAgICAgICAgICAgICAgdmFycyhmYWN0b3JfbGFiZGVzY3JpcHRfQSksCiAgICAgICAgICAgICAgICAgIGZ1bnMoZ3N1YigiIFxcKCIsICJcblxcKCIsIC4pKSkgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGVfYXQoI3ZhcnMoY29udGFpbnMoImxhYmRlc2NyaXB0IikpLAogICAgICAgICAgICAgICAgICB2YXJzKGZhY3Rvcl9sYWJkZXNjcmlwdF9BKSwKICAgICAgICAgICAgICAgICAgZnVucyhnc3ViKCJcXC8iLCAiXFwvXG4iLCAuKSkpLCAKICAgICAgICAgICAgICB3aGljaF9jb3VudHJ5ID0gIlZhbnVhdHUiKSArCiAgeWxpbShtaW5fY29uZ19hZHVsdHMkbWluX2NvbmcsIDEpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWdTMDRfb3J0aG9nb25hbC5wbmciKQpgYGAKCmBgYHtyIGJvZHkgbWluZCBjb25nIGFkdWx0c30KIyAiSW4gZWFjaCBzYW1wbGUsIHRoZXJlIHdhcyBhIGZhY3RvciB0aGF0IHdhcyBzaW1pbGFyIHRvIFVTIGFkdWx0c+KAmSDigJxib2R54oCdIGZhY3Rvci4uLgpjb25nX2RmX2FkdWx0cyAlPiUgCiAgZmlsdGVyKGdyZXBsKCJib2R5IiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHRfQSkpLCAKICAgICAgICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9CKSksCiAgICAgICAgIGNvdW50cnlfQSAhPSAiVVMiLCBjb3VudHJ5X0IgPT0gIlVTIikKCiMgIi4uLmFuZCBub3Qgc2ltaWxhciB0byB0aGUgVVMgYWR1bHQg4oCcbWluZOKAnSBmYWN0b3IsIC4uLgpjb25nX2RmX2FkdWx0cyAlPiUgCiAgZmlsdGVyKGdyZXBsKCJib2R5IiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHRfQSkpLCAKICAgICAgICAgZ3JlcGwoIm1pbmQiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9CKSksCiAgICAgICAgIGNvdW50cnlfQSAhPSAiVVMiLCBjb3VudHJ5X0IgPT0gIlVTIikKCiMgIi4uLiBhbmQgYSBmYWN0b3IgdGhhdCB3YXMgbXVjaCBtb3JlIHNpbWlsYXIgdG8gVVMgYWR1bHRz4oCZIOKAnG1pbmTigJ0gZmFjdG9yLi4uCmNvbmdfZGZfYWR1bHRzICU+JSAKICBmaWx0ZXIoZ3JlcGwoIm1pbmQiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9BKSksIAogICAgICAgICBncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0IpKSwKICAgICAgICAgY291bnRyeV9BICE9ICJVUyIsIGNvdW50cnlfQiA9PSAiVVMiKQoKIyAiLi4udGhhbiB0aGUgVVMgYWR1bHQg4oCcYm9keeKAnSBmYWN0b3IuIgpjb25nX2RmX2FkdWx0cyAlPiUgCiAgZmlsdGVyKGdyZXBsKCJtaW5kIiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHRfQSkpLCAKICAgICAgICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9CKSksCiAgICAgICAgIGNvdW50cnlfQSAhPSAiVVMiLCBjb3VudHJ5X0IgPT0gIlVTIikKYGBgCmBgYHtyIGhlYXJ0IGNvbmcgYWR1bHRzfQpjb25nX2RmX2FkdWx0cyAlPiUgCiAgZmlsdGVyKGdyZXBsKCJoZWFydCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0EpKSwgCiAgICAgICAgIGdyZXBsKCJoZWFydCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0IpKSwKICAgICAgICAgY291bnRyeV9BICVpbiUgYygiVGhhaWxhbmQiLCAiQ2hpbmEiKSwgY291bnRyeV9CID09ICJVUyIpCgpjb25nX2RmX2FkdWx0cyAlPiUgCiAgZmlsdGVyKGdyZXBsKCJib2R5IiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHRfQSkpIHwgCiAgICAgICAgICAgZ3JlcGwoIm1pbmQiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9BKSksCiAgICAgICAgIGdyZXBsKCJoZWFydCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0IpKSwKICAgICAgICAgY291bnRyeV9BICVpbiUgYygiVGhhaWxhbmQiLCAiQ2hpbmEiKSwgY291bnRyeV9CID09ICJVUyIpCmBgYAoKCiMgQ2hpbGRyZW4KCiMjIFNhbXBsZXMKCmBgYHtyIHNhbXBsZXMgY2hpbGRyZW59CmJpbmRfcm93cyhkX3VzX2NoaWxkcmVuLCBkX2doX2NoaWxkcmVuLCBkX3RoX2NoaWxkcmVuLCBkX2NoX2NoaWxkcmVuLCBkX3Z0X2NoaWxkcmVuKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBsZXZlbHNfY291bnRyeSkpICU+JQogIGRpc3RpbmN0KGNvdW50cnksIHN1YmpfaWQpICU+JQogIGNvdW50KGNvdW50cnkpICU+JSAKICBqYW5pdG9yOjphZG9ybl90b3RhbHMoKQpgYGAKCiMjIFNjYWxlIHVzZQoKYGBge3Igc2NhbGUgdXNlIG1lYW4gb3ZlcmFsbCBjaGlsZHJlbn0KYmluZF9yb3dzKGRfdXNfY2hpbGRyZW4sIGRfZ2hfY2hpbGRyZW4sIGRfdGhfY2hpbGRyZW4sIGRfY2hfY2hpbGRyZW4sIGRfdnRfY2hpbGRyZW4pICU+JQogIG11dGF0ZShjb3VudHJ5ID0gZmFjdG9yKGNvdW50cnksIGxldmVscyA9IGxldmVsc19jb3VudHJ5KSwKICAgICAgICAgcmVzcG9uc2VfY2F0ID0gcmVjb2RlX2ZhY3RvcihyZXNwb25zZV9jYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vIiA9ICJubyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImtpbmQgb2YiID0gImtpbmQgb2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ5ZXMiID0gInllcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5taXNzaW5nID0gIm1pc3NpbmcgZGF0YSIpKSAlPiUKICBjb3VudChjb3VudHJ5LCByZXNwb25zZV9jYXQpICU+JQogIGNvbXBsZXRlKHJlc3BvbnNlX2NhdCwgbmVzdGluZyhjb3VudHJ5KSwgZmlsbCA9IGxpc3QobiA9IDApKSAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBtdXRhdGUocHJvcCA9IG4vc3VtKG4sIG5hLnJtID0gVCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW4pICU+JQogIHNwcmVhZChyZXNwb25zZV9jYXQsIHByb3ApICU+JQogIGphbml0b3I6OmFkb3JuX3BjdF9mb3JtYXR0aW5nKGRpZ2l0cyA9IDIpCmBgYAoKIyMgRmFjdG9yIHJldGVudGlvbjogcGFyYWxsZWwgYW5hbHlzaXMKCmBgYHtyIHBhcmFsbGVsIGRpc3QgY2hpbGRyZW4sIGZpZy53aWR0aCA9IDMsIGZpZy5hc3AgPSAwLjV9CiMgSGVyZSdzIHRoZSBkaXN0cmlidXRpb24gb3ZlciBvdXRjb21lcyBvZiBwYXJhbGxlbCBhbmFseXNpcyB3aXRoIDEwMCBpdGVyYXRpb25zLiBXZSdsbCBjaG9vc2UgdGhlIG1lZGlhbiBudW1iZXIgb2YgZmFjdG9ycy4KCmlmIChmaWxlLmV4aXN0cygiLi4vcmVzdWx0cy9wYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuLlJEUyIpKSB7CiAgCiAgcGFfb3V0Y29tZXNfZGlzdF9jaGlsZHJlbiA8LSByZWFkUkRTKCIuLi9yZXN1bHRzL3BhX291dGNvbWVzX2Rpc3RfY2hpbGRyZW4uUkRTIikKICAKfSBlbHNlIHsKICAKICBwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuIDwtIGRhdGEuZnJhbWUodXMgPSBOVUxMLCBnaCA9IE5VTEwsIHRoID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2ggPSBOVUxMLCB2dCA9IE5VTEwpCiAgCiAgc2V0LnNlZWQoNTQzMjEpCiAgbl9jb3JlcyA8LSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKQogIG9wdGlvbnMobWMuY29yZXMgPSBuX2NvcmVzKQogIAogIGZvciAoaSBpbiAxOjEwMCkgewogICAgcGFfb3V0Y29tZXNfZGlzdF9jaGlsZHJlbltpLCAidXMiXSA8LSBmYS5wYXJhbGxlbChkX3VzX2NoaWxkcmVuX3csIHBsb3QgPSBGKSRuZmFjdAogICAgcGFfb3V0Y29tZXNfZGlzdF9jaGlsZHJlbltpLCAiZ2giXSA8LSBmYS5wYXJhbGxlbChkX2doX2NoaWxkcmVuX3csIHBsb3QgPSBGKSRuZmFjdCAgICAgCiAgICBwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuW2ksICJ0aCJdIDwtIGZhLnBhcmFsbGVsKGRfdGhfY2hpbGRyZW5fdywgcGxvdCA9IEYpJG5mYWN0CiAgICBwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuW2ksICJjaCJdIDwtIGZhLnBhcmFsbGVsKGRfY2hfY2hpbGRyZW5fdywgcGxvdCA9IEYpJG5mYWN0CiAgICBwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuW2ksICJ2dCJdIDwtIGZhLnBhcmFsbGVsKGRfdnRfY2hpbGRyZW5fdywgcGxvdCA9IEYpJG5mYWN0CiAgfQogIAogIHNhdmVSRFMocGFfb3V0Y29tZXNfZGlzdF9jaGlsZHJlbiwgZmlsZSA9ICIuLi9yZXN1bHRzL3BhX291dGNvbWVzX2Rpc3RfY2hpbGRyZW4uUkRTIikKfQoKIyBwbG90CnBhX291dGNvbWVzX2Rpc3RfY2hpbGRyZW4gJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJpdGVyIikgJT4lCiAgZ2F0aGVyKGNvdW50cnksIG5mYWN0LCAtaXRlcikgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBmYWN0b3IoY291bnRyeSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJ1cyIsICJnaCIsICJ0aCIsICJjaCIsICJ2dCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxldmVsc19jb3VudHJ5KSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbmZhY3QpKSArCiAgZmFjZXRfZ3JpZCh+IGNvdW50cnkpICsKICBnZW9tX2JhcihzdGF0ID0gImNvdW50IikgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDEsIG1heChwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuKSArIDEpLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAwLCAxKSkgKwogIGxhYnMoeCA9ICJOdW1iZXIgb2YgZmFjdG9ycyBzdWdnZXN0ZWQgYnkgZmEucGFyYWxsZWwoKSIpCmBgYAoKIyMgRXhwbG9yYXRvcnkgZmFjdG9yIGFuYWx5c2lzCgpgYGB7ciBlZmEgY2hpbGRyZW59CnNldC5zZWVkKDU0MzIxKQoKIyBkbyBleHBsb3JhdG9yeSBmYWN0b3IgYW5hbHlzaXM6IGNoaWxkcmVuCmVmYV91c19jaGlsZHJlbiA8LSBmYV9mdW4oZF91c19jaGlsZHJlbl93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbWVkaWFuKHBhX291dGNvbWVzX2Rpc3RfY2hpbGRyZW4kdXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9yb3QgPSAidmFyaW1heCIpCmNvbG5hbWVzKGVmYV91c19jaGlsZHJlbiRsb2FkaW5ncykgPC0gcGFzdGUwKCJ1c0NISUxEUkVOXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhlZmFfdXNfY2hpbGRyZW4kbG9hZGluZ3MpKQoKZWZhX2doX2NoaWxkcmVuIDwtIGZhX2Z1bihkX2doX2NoaWxkcmVuX3csCiAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuJGdoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fbi5pdGVyID0gMTAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfZ2hfY2hpbGRyZW4kbG9hZGluZ3MpIDwtIHBhc3RlMCgiZ2hDSElMRFJFTl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX2doX2NoaWxkcmVuJGxvYWRpbmdzKSkKCmVmYV90aF9jaGlsZHJlbiA8LSBmYV9mdW4oZF90aF9jaGlsZHJlbl93LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbWVkaWFuKHBhX291dGNvbWVzX2Rpc3RfY2hpbGRyZW4kdGgpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9uLml0ZXIgPSAxMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNob3Nlbl9yb3QgPSAidmFyaW1heCIpCmNvbG5hbWVzKGVmYV90aF9jaGlsZHJlbiRsb2FkaW5ncykgPC0gcGFzdGUwKCJ0aENISUxEUkVOXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhlZmFfdGhfY2hpbGRyZW4kbG9hZGluZ3MpKQoKZWZhX2NoX2NoaWxkcmVuIDwtIGZhX2Z1bihkX2NoX2NoaWxkcmVuX3csIAogICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBtZWRpYW4ocGFfb3V0Y29tZXNfZGlzdF9jaGlsZHJlbiRjaCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2hvc2VuX24uaXRlciA9IDEwMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2hvc2VuX3JvdCA9ICJ2YXJpbWF4IikKY29sbmFtZXMoZWZhX2NoX2NoaWxkcmVuJGxvYWRpbmdzKSA8LSBwYXN0ZTAoImNoQ0hJTERSRU5fIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKGVmYV9jaF9jaGlsZHJlbiRsb2FkaW5ncykpCgplZmFfdnRfY2hpbGRyZW4gPC0gZmFfZnVuKGRfdnRfY2hpbGRyZW5fdywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG1lZGlhbihwYV9vdXRjb21lc19kaXN0X2NoaWxkcmVuJHZ0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fbi5pdGVyID0gMTAwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICBjaG9zZW5fcm90ID0gInZhcmltYXgiKQpjb2xuYW1lcyhlZmFfdnRfY2hpbGRyZW4kbG9hZGluZ3MpIDwtIHBhc3RlMCgidnRDSElMRFJFTl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX3Z0X2NoaWxkcmVuJGxvYWRpbmdzKSkKYGBgCgpgYGB7ciBmYWN0b3IgbmFtZXMgY2hpbGRyZW59CmZhY3Rvcl9uYW1lc19jaGlsZHJlbiA8LSBkYXRhLmZyYW1lKGZhY3RvciA9IGMoY29sbmFtZXMoZWZhX3VzX2NoaWxkcmVuJGxvYWRpbmdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhlZmFfZ2hfY2hpbGRyZW4kbG9hZGluZ3MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKGVmYV90aF9jaGlsZHJlbiRsb2FkaW5ncyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoZWZhX2NoX2NoaWxkcmVuJGxvYWRpbmdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhlZmFfdnRfY2hpbGRyZW4kbG9hZGluZ3MpKSkgJT4lCiAgbXV0YXRlKGFnZV9ncm91cCA9ICJjaGlsZHJlbiIpICU+JQogIG11dGF0ZShjb3VudHJ5ID0gY2FzZV93aGVuKGdyZXBsKCJedXMiLCBmYWN0b3IpIH4gIlVTIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiXmdoIiwgZmFjdG9yKSB+ICJHaGFuYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIl50aCIsIGZhY3RvcikgfiAiVGhhaWxhbmQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJeY2giLCBmYWN0b3IpIH4gIkNoaW5hIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiXnZ0IiwgZmFjdG9yKSB+ICJWYW51YXR1IiksCiAgICAgICAgIGNvdW50cnkgPSBmYWN0b3IoY291bnRyeSwgbGV2ZWxzX2NvdW50cnkpKSAlPiUKICBtdXRhdGUoZmFjdG9yX25hbWUgPSBnc3ViKCJedXMiLCAiVVMgIiwgZmFjdG9yKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJeZ2giLCAiR2guICIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJedGgiLCAiVGguICIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJeY2giLCAiQ2guICIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJednQiLCAiVmEuICIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJDSElMRFJFTiIsICJjaGlsZHJlbiIsIGZhY3Rvcl9uYW1lKSwKICAgICAgICAgZmFjdG9yX25hbWUgPSBnc3ViKCJfRiIsICIgRmFjdG9yICIsIGZhY3Rvcl9uYW1lKSkgJT4lCiAgbXV0YXRlKGZhY3Rvcl9kZXNjcmlwdCA9IHJlY29kZShmYWN0b3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c0NISUxEUkVOX0YxID0gIkJvZHktbGlrZSwgbmVnYXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNDSElMRFJFTl9GMyA9ICJIZWFydC1saWtlLCBwb3NpdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c0NISUxEUkVOX0YyID0gIk1pbmQtbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnaENISUxEUkVOX0YxID0gIkJvZHktbGlrZSwgbmVnYXRpdmUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2hDSElMRFJFTl9GMiA9ICJNaW5kLWxpa2UsIHBvc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdoQ0hJTERSRU5fRjMgPSAiUHJheSwgYWRkLCBldGMuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoQ0hJTERSRU5fRjEgPSAiQm9keS1saWtlLCBwb3NpdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aENISUxEUkVOX0YyID0gIkhlYXJ0LWxpa2UsIG5lZ2F0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoQ0hJTERSRU5fRjMgPSAiTWluZC1saWtlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoQ0hJTERSRU5fRjQgPSAiQWRkLCBwcmF5LCBldGMuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoQ0hJTERSRU5fRjEgPSAiSGVhcnQtbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaENISUxEUkVOX0YyID0gIkJvZHktbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaENISUxEUkVOX0YzID0gIk1pbmQtbGlrZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaENISUxEUkVOX0Y0ID0gIlByYXksIGV0Yy4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdnRDSElMRFJFTl9GMSA9ICJCb2R5LWxpa2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdnRDSElMRFJFTl9GMiA9ICJNaW5kLWxpa2UsIHBvc2l0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZ0Q0hJTERSRU5fRjMgPSAiSGVhcnQtbGlrZSwgbmVnYXRpdmUiKSwKICAgICAgICAgZmFjdG9yX2xhYmRlc2NyaXB0ID0gcGFzdGUoZ3N1YigiLipfRiIsICJGIiwgZmFjdG9yKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9yX2Rlc2NyaXB0LCBzZXAgPSAiOiAiKSkKYGBgCgojIyBGYWN0b3IgbG9hZGluZ3MKCmBgYHtyIG9yZGVyIGNoaWxkcmVufQojIG9yZGVyIGNhcGFjaXRpZXM6IGNoaWxkcmVuCm9yZGVyX3VzX2NoaWxkcmVuIDwtIGZhLnNvcnQoZWZhX3VzX2NoaWxkcmVuKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX2doX2NoaWxkcmVuIDwtIGZhLnNvcnQoZWZhX2doX2NoaWxkcmVuKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX3RoX2NoaWxkcmVuIDwtIGZhLnNvcnQoZWZhX3RoX2NoaWxkcmVuKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX2NoX2NoaWxkcmVuIDwtIGZhLnNvcnQoZWZhX2NoX2NoaWxkcmVuKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCm9yZGVyX3Z0X2NoaWxkcmVuIDwtIGZhLnNvcnQoZWZhX3Z0X2NoaWxkcmVuKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpCmBgYAoKYGBge3IgbG9hZGluZ3MgY2hpbGRyZW59CiMgY29tcGlsZSBsb2FkaW5nczogY2hpbGRyZW4KbG9hZGluZ3NfY2hpbGRyZW4gPC0gYmluZF9yb3dzKAogIGxvYWRpbmdzX2Z1bihlZmFfdXNfY2hpbGRyZW4pICU+JSBtdXRhdGUoY291bnRyeSA9ICJVUyIpLAogIGxvYWRpbmdzX2Z1bihlZmFfZ2hfY2hpbGRyZW4pICU+JSBtdXRhdGUoY291bnRyeSA9ICJHaGFuYSIpLAogIGxvYWRpbmdzX2Z1bihlZmFfdGhfY2hpbGRyZW4pICU+JSBtdXRhdGUoY291bnRyeSA9ICJUaGFpbGFuZCIpLAogIGxvYWRpbmdzX2Z1bihlZmFfY2hfY2hpbGRyZW4pICU+JSBtdXRhdGUoY291bnRyeSA9ICJDaGluYSIpLAogIGxvYWRpbmdzX2Z1bihlZmFfdnRfY2hpbGRyZW4pICU+JSBtdXRhdGUoY291bnRyeSA9ICJWYW51YXR1IikpICU+JQogIG11dGF0ZShjb3VudHJ5ID0gZmFjdG9yKGNvdW50cnksIGxldmVscyA9IGxldmVsc19jb3VudHJ5KSwKICAgICAgICAgY2FwYWNpdHlfb3JkX3VzID0gZmFjdG9yKGNhcGFjaXR5LCBsZXZlbHMgPSBvcmRlcl91c19jaGlsZHJlbiksCiAgICAgICAgIGNhcGFjaXR5X29yZF9naCA9IGZhY3RvcihjYXBhY2l0eSwgbGV2ZWxzID0gb3JkZXJfZ2hfY2hpbGRyZW4pLAogICAgICAgICBjYXBhY2l0eV9vcmRfdGggPSBmYWN0b3IoY2FwYWNpdHksIGxldmVscyA9IG9yZGVyX3RoX2NoaWxkcmVuKSwKICAgICAgICAgY2FwYWNpdHlfb3JkX2NoID0gZmFjdG9yKGNhcGFjaXR5LCBsZXZlbHMgPSBvcmRlcl9jaF9jaGlsZHJlbiksCiAgICAgICAgIGNhcGFjaXR5X29yZF92dCA9IGZhY3RvcihjYXBhY2l0eSwgbGV2ZWxzID0gb3JkZXJfdnRfY2hpbGRyZW4pKSAlPiUKICBhcnJhbmdlKGNvdW50cnksIGZhY3RvciwgZGVzYyhhYnMobG9hZGluZykpLCBjYXBhY2l0eSkgJT4lCiAgbXV0YXRlKG9yZGVyID0gMTpucm93KC4pKSAlPiUKICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2NoaWxkcmVuKQpgYGAKCmBgYHtyIGhlYXRtYXAgY2hpbGRyZW4sIGZpZy53aWR0aCA9IDUsIGZpZy5hc3AgPSAwLjd9CiMgbWFrZSBoZWF0bWFwIGZpZ3VyZTogY2hpbGRyZW4KbG9hZGluZ3NfY2hpbGRyZW4gJT4lCiAgbXV0YXRlKGZhY3Rvcl9udW0gPSBhcy5udW1lcmljKGdzdWIoIi4qRiIsICIiLCBmYWN0b3IpKSkgJT4lCiAgbXV0YXRlKHNhbXBsZSA9IHBhc3RlKGNvdW50cnksICJjaGlsZHJlbiIsIHNlcCA9ICJcbiIpKSAlPiUKICBsZWZ0X2pvaW4oZmFjdG9yX25hbWVzX2NoaWxkcmVuKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBsZXZlbHNfY291bnRyeSkpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZmFjdG9yX2xhYmRlc2NyaXB0LCBmYWN0b3JfbnVtKSwgCiAgICAgICAgICAgICB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfdXMpKSwKICAgICAgICAgICAgICMgeSA9IHJlb3JkZXIoY2FwYWNpdHksIGRlc2MoY2FwYWNpdHlfb3JkX2VjKSksIAogICAgICAgICAgICAgIyB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfZ2gpKSwKICAgICAgICAgICAgICMgeSA9IHJlb3JkZXIoY2FwYWNpdHksIGRlc2MoY2FwYWNpdHlfb3JkX3RoKSksCiAgICAgICAgICAgICAjIHkgPSByZW9yZGVyKGNhcGFjaXR5LCBkZXNjKGNhcGFjaXR5X29yZF9jaCkpLAogICAgICAgICAgICAgIyB5ID0gcmVvcmRlcihjYXBhY2l0eSwgZGVzYyhjYXBhY2l0eV9vcmRfdnQpKSwKICAgICAgICAgICAgIGZpbGwgPSBsb2FkaW5nKSkgKwogIGZhY2V0X2dyaWQofiByZW9yZGVyKHNhbXBsZSwgYXMubnVtZXJpYyhjb3VudHJ5KSksIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdChyb3VuZChsb2FkaW5nLCAyKSwgbnNtYWxsID0gMikpLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiUmRZbEJ1IiwgbGltaXRzID0gYygtMSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihiYXJoZWlnaHQgPSAyMCwgYmFyd2lkdGggPSAwLjUpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSksCiAgICAgICAgcGFuZWwuc3BhY2luZy54ID0gdW5pdCgwLjgsICJsaW5lcyIpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpKSArCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJDYXBhY2l0eSIsIGZpbGwgPSAiRmFjdG9yXG5sb2FkaW5nIikKYGBgCgojIyBDb25ncnVlbmNlCgpTZWUgW0FsbCBzYW1wbGVzXSwgYmVsb3cuCgojIyBCb290c3RyYXBwZWQgY29uZ3J1ZW5jZQoKYGBge3IgYm9vdHN0cmFwIGNvbmdydWVuY2UgY2hpbGRyZW59CmlmIChmaWxlLmV4aXN0cygiLi4vcmVzdWx0cy9jb25nX2RmX2NoaWxkcmVuX29ydGhvZ29uYWwuUkRTIikpIHsKICAKICBjb25nX2RmX2NoaWxkcmVuIDwtIHJlYWRSRFMoIi4uL3Jlc3VsdHMvY29uZ19kZl9jaGlsZHJlbl9vcnRob2dvbmFsLlJEUyIpCiAgCn0gZWxzZSB7CiAgCiAgYnNfY2hpbGRyZW4gPC0gbG9hZGluZ3NfY2hpbGRyZW4gJT4lCiAgICBzZWxlY3QoY2FwYWNpdHksIGZhY3RvciwgbG9hZGluZykgJT4lCiAgICBzcHJlYWQoZmFjdG9yLCBsb2FkaW5nKSAlPiUKICAgIGZ1bGxfam9pbihsb2FkaW5nc19hZHVsdHMgJT4lCiAgICAgICAgICAgICAgICBzZWxlY3QoY2FwYWNpdHksIGZhY3RvciwgbG9hZGluZykgJT4lCiAgICAgICAgICAgICAgICBzcHJlYWQoZmFjdG9yLCBsb2FkaW5nKSkgJT4lCiAgICBzZWxlY3QoLWNhcGFjaXR5KSAlPiUKICAgIHNqc3RhdHM6OmJvb3RzdHJhcCgxMDAwKSAKICAKICBjb25nX2RmX2NoaWxkcmVuIDwtIGRhdGEuZnJhbWUoTlVMTCkKICAKICBmb3IgKGsgaW4gbGV2ZWxzX2NvdW50cnkpIHsKICAgIAogICAgZmFjdG9yc19jaGlsZHJlbiA8LSBsZXZlbHMoZmFjdG9yKGxvYWRpbmdzX2NoaWxkcmVuJGZhY3RvclsKICAgICAgbG9hZGluZ3NfY2hpbGRyZW4kY291bnRyeSA9PSBrXSkpCiAgICBmYWN0b3JzX2FkdWx0cyA8LSBsZXZlbHMoZmFjdG9yKGxvYWRpbmdzX2FkdWx0cyRmYWN0b3JbCiAgICAgIGxvYWRpbmdzX2FkdWx0cyRjb3VudHJ5ID09IGtdKSkKICAgIAogICAgZm9yIChpIGluIGZhY3RvcnNfY2hpbGRyZW4pIHsKICAgICAgZm9yIChqIGluIGZhY3RvcnNfYWR1bHRzKSB7CiAgICAgICAgY25hbWUgPC0gcGFzdGUoaSwgaiwgc2VwID0gIi4iKQogICAgICAgIHRlbXAgPC0gYnNfY2hpbGRyZW4gJT4lCiAgICAgICAgICBtdXRhdGUoY29uZyA9IG1hcF9kYmwoc3RyYXAsIH5sc2E6OmNvc2luZShhcy5kYXRhLmZyYW1lKC54KVssaV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lKC54KVssal0pKSkKICAgICAgICBjb25nX2RmX2NoaWxkcmVuWzE6MTAwMCwgY25hbWVdIDwtIHRlbXAkY29uZwogICAgICB9CiAgICB9CiAgICAKICAgIHJtKGksIGosIGNuYW1lLCB0ZW1wLCBmYWN0b3JzX2NoaWxkcmVuLCBmYWN0b3JzX2FkdWx0cykKICAgIAogIH0KICAKICBybShrKQogIAogIGNvbmdfZGZfY2hpbGRyZW4gPC0gY29uZ19kZl9jaGlsZHJlbiAlPiUKICAgIGdhdGhlcihmYWN0b3JfcGFpciwgY29uZykgJT4lCiAgICBzZXBhcmF0ZShmYWN0b3JfcGFpciwgaW50byA9IGMoImZhY3Rvcl9BIiwgImZhY3Rvcl9CIiksIHNlcCA9ICJcXC4iKSAlPiUKICAgIGdyb3VwX2J5KGZhY3Rvcl9BLCBmYWN0b3JfQikgJT4lCiAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oY29uZyksCiAgICAgICAgICAgICAgY2lfbG93ZXIgPSBjaV9sb3dlcihjb25nKSwKICAgICAgICAgICAgICBjaV91cHBlciA9IGNpX3VwcGVyKGNvbmcpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIGZ1bGxfam9pbihmYWN0b3JfbmFtZXNfY2hpbGRyZW4gJT4lCiAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkEiLCBzZXAgPSAiXyIpKSkpICU+JQogICAgZnVsbF9qb2luKGZhY3Rvcl9uYW1lc19hZHVsdHMgJT4lCiAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkIiLCBzZXAgPSAiXyIpKSkpICU+JQogICAgbXV0YXRlKGZhY3Rvcl9iaG1fQSA9IGNhc2Vfd2hlbigKICAgICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9BKSkgfiAiQm9keS1saWtlXG5jaGlsZCBmYWN0b3IiLAogICAgICBncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0EpKSB+ICJNaW5kLWxpa2VcbmNoaWxkIGZhY3RvciIsCiAgICAgIGdyZXBsKCJoZWFydCIsIHRvbG93ZXIoZmFjdG9yX2Rlc2NyaXB0X0EpKSB+ICJIZWFydC1saWtlXG5jaGlsZCBmYWN0b3IiLAogICAgICBUUlVFIH4gIk90aGVyIikpICU+JQogICAgbXV0YXRlKGZhY3Rvcl9iaG1fQiA9IGNhc2Vfd2hlbigKICAgICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9CKSkgfiAiTG9jYWwgYWR1bHRzOlxuQm9keS1saWtlIGZhY3RvciIsCiAgICAgIGdyZXBsKCJtaW5kIiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHRfQikpIH4gIkxvY2FsIGFkdWx0czpcbk1pbmQtbGlrZSBmYWN0b3IiLAogICAgICBncmVwbCgiaGVhcnQiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdF9CKSkgfiAiTG9jYWwgYWR1bHRzOlxuSGVhcnQtbGlrZSBmYWN0b3IiLAogICAgICBUUlVFIH4gIkxvY2FsIGFkdWx0czpcbk90aGVyIGZhY3RvciIpKQogIAogIHNhdmVSRFMoY29uZ19kZl9jaGlsZHJlbiwgZmlsZSA9ICIuLi9yZXN1bHRzL2NvbmdfZGZfY2hpbGRyZW5fb3J0aG9nb25hbC5SRFMiKQp9CmBgYAoKYGBge3IgY29uZyBtaW4gY2hpbGRyZW59CiMgZmluZCBtaW5pbXVtIHZhbHVlIHRvIHNldCBjb25zdGFudCBsb3dlciBib3VuZCBvZiBwbG90cwptaW5fY29uZ19jaGlsZHJlbiA8LSBjb25nX2RmX2NoaWxkcmVuICU+JQogIHN1bW1hcmlzZShtaW5fY29uZyA9IG1pbihjaV9sb3dlciwgbmEucm0gPSBUKSkKYGBgCgpgYGB7ciBjb25nIGNpcyBjaGlsZHJlbiwgZmlnLndpZHRoID0gNCwgZmlnLmFzcCA9IDEuNH0KIyBGSUdVUkUgNAojIGZpZy5hc3AgY2hvc2VuIHRvIGtlZXAgYWJzb2x1dGUgaGVpZ2h0IG9mIHktYXhpcyByZWxhdGl2ZWx5IHNpbWlsYXIgYWNyb3NzIGFkdWx0cyBhbmQgY2hpbGRyZW4KY29uZ19kZl9jaGlsZHJlbiAlPiUKICBtdXRhdGUocmVnaW9uX0EgPSBjYXNlX3doZW4oCiAgICBjb3VudHJ5X0EgPT0gIlVTIiB+ICJTRiBCYXkgQXJlYSIsCiAgICBjb3VudHJ5X0EgPT0gIkdoYW5hIiB+ICJDYXBlIENvYXN0IiwKICAgIGNvdW50cnlfQSA9PSAiVGhhaWxhbmQiIH4gIkNoaWFuZyBNYWkiLAogICAgY291bnRyeV9BID09ICJDaGluYSIgfiAiU2hhbmdoYWkiLAogICAgY291bnRyeV9BID09ICJWYW51YXR1IiB+ICJQViAmIE1hbGVrdWxhIikpICU+JQogIG11dGF0ZShzYW1wbGVfQSA9IHBhc3RlKGNvdW50cnlfQSwgYWdlX2dyb3VwX0EsIHNlcCA9ICJcbiIpKSAlPiUKICBtdXRhdGUobGFiX0EgPSBwYXN0ZShwYXN0ZTAocmVnaW9uX0EsICIsIiksIAogICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCh0b3VwcGVyKGNvdW50cnlfQSksICI6IiksIAogICAgICAgICAgICAgICAgICAgICAgIGFnZV9ncm91cF9BLCBzZXAgPSAiXG4iKSkgJT4lCiAgbXV0YXRlKGJobV9BID0gY2FzZV93aGVuKAogICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9sYWJkZXNjcmlwdF9BKSkgfiAiYm9keSIsCiAgICBncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2xhYmRlc2NyaXB0X0EpKSB+ICJtaW5kIiwKICAgIGdyZXBsKCJoZWFydCIsIHRvbG93ZXIoZmFjdG9yX2xhYmRlc2NyaXB0X0EpKSB+ICJoZWFydCIsIAogICAgVFJVRSB+ICJvdGhlciIpKSAlPiUKICBtdXRhdGUoYmhtX0EgPSBmYWN0b3IoYmhtX0EsIGxldmVscyA9IGMoImJvZHkiLCAiaGVhcnQiLCAibWluZCIsICJvdGhlciIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihmYWN0b3JfbGFiZGVzY3JpcHRfQSwgYXMubnVtZXJpYyhiaG1fQSkpLCB5ID0gbWVhbikpICsKICBmYWNldF9ncmlkKGZhY3Rvcl9iaG1fQiB+IHJlb3JkZXIobGFiX0EsIGFzLm51bWVyaWMoY291bnRyeV9BKSksIAogICAgICAgICAgICAgc2NhbGVzID0gImZyZWVfeCIsIHNwYWNlID0gImZyZWVfeCIpICsKICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLCB5bWluID0gLUluZiwgeW1heCA9IDAuODUsCiAgICAgICAgICAgZmlsbCA9ICJncmF5MjAiLCBhbHBoYSA9IDAuMikgKwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsIHltaW4gPSAwLjg1LCB5bWF4ID0gMC45NSwKICAgICAgICAgICBmaWxsID0gdmlyaWRpc0xpdGU6OnZpcmlkaXMoMiwgYmVnaW4gPSAwLjc1LzIsIGVuZCA9IDAuNzUpWzFdLCBhbHBoYSA9IDAuMikgKwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsIHltaW4gPSAwLjk1LCB5bWF4ID0gSW5mLAogICAgICAgICAgIGZpbGwgPSB2aXJpZGlzTGl0ZTo6dmlyaWRpcygyLCBiZWdpbiA9IDAuNzUvMiwgZW5kID0gMC43NSlbMl0sIGFscGhhID0gMC4yKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC44NSwgbHR5ID0gMiwgY29sb3IgPSAiZ3JheTEwIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuOTUsIGx0eSA9IDIsIGNvbG9yID0gImdyYXkxMCIpICsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwKICAgICAgICAgICAgICAgICAgZmF0dGVuID0gMywKICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdChyb3VuZChtZWFuLCAyKSwgbnNtYWxsID0gMiksCiAgICAgICAgICAgICAgICB5ID0gaWZlbHNlKGNpX2xvd2VyIDwgMC4yLCBjaV91cHBlciArIDAuMDUsIGNpX2xvd2VyIC0gMC4wNSksCiAgICAgICAgICAgICAgICB2anVzdCA9IGlmZWxzZShjaV9sb3dlciA8IDAuMiwgMCwgMSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgtMSwgMSwgMC4yKSwKICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMDUpKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBhZXN0aGV0aWNzID0gYygiY29sb3IiLCAiZmlsbCIpKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IDIxOjI1KSArCiAgbGFicyh4ID0gTlVMTCwKICAgICAgIHkgPSBleHByZXNzaW9uKCJTaW1pbGFyaXR5ICIoaXRhbGljKHJbY10pKSkpICsgCiAgZ3VpZGVzKGNvbG9yID0gIm5vbmUiLCBmaWxsID0gIm5vbmUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IHNjYWxlczo6YWxwaGEoIndoaXRlIiwgMCksIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYyg1LjUsIDUuNSwgNS41LCAxNS41KSwgInBvaW50IikpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWcwNF9vcnRob2dvbmFsLnBuZyIpCmBgYAoKYGBge3IgYm9keSBtaW5kIGNvbmcgY2hpbGRyZW59CiMgIkluIGVhY2ggc2FtcGxlLCB0aGVyZSB3YXMgYSBmYWN0b3IgdGhhdCB3YXMgbXVjaCBtb3JlIHNpbWlsYXIgdG8gbG9jYWwgYWR1bHRz4oCZIOKAnGJvZHktbGlrZeKAnSBmYWN0b3IuLi4KY29uZ19kZl9jaGlsZHJlbiAlPiUgCiAgZmlsdGVyKGdyZXBsKCJib2R5IiwgdG9sb3dlcihmYWN0b3JfYmhtX0EpKSwgCiAgICAgICAgIGdyZXBsKCJib2R5IiwgdG9sb3dlcihmYWN0b3JfYmhtX0IpKSkKCiMgIi4uLnRoYW4gdGhlaXIg4oCcbWluZC1saWtl4oCdIGZhY3RvciwgLi4uCmNvbmdfZGZfY2hpbGRyZW4gJT4lIAogIGZpbHRlcihncmVwbCgiYm9keSIsIHRvbG93ZXIoZmFjdG9yX2JobV9BKSksIAogICAgICAgICBncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2JobV9CKSkpCgojICIuLi4gYW5kIGEgZmFjdG9yIHRoYXQgd2FzIG11Y2ggbW9yZSBzaW1pbGFyIHRvIGxvY2FsIGFkdWx0c+KAmSDigJxtaW5kLWxpa2XigJ0gZmFjdG9yLi4uCmNvbmdfZGZfY2hpbGRyZW4gJT4lIAogIGZpbHRlcihncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2JobV9BKSksIAogICAgICAgICBncmVwbCgibWluZCIsIHRvbG93ZXIoZmFjdG9yX2JobV9CKSkpCgojICIuLi50aGFuIHRoZWlyIOKAnGJvZHktbGlrZeKAnSBmYWN0b3IuIgpjb25nX2RmX2NoaWxkcmVuICU+JSAKICBmaWx0ZXIoZ3JlcGwoIm1pbmQiLCB0b2xvd2VyKGZhY3Rvcl9iaG1fQSkpLCAKICAgICAgICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9iaG1fQikpKQpgYGAKCgojIEFsbCBzYW1wbGVzCgojIyBDb25ncnVlbmNlCgpgYGB7ciBjb25ncnVlbmNlIGFsbCBzYW1wbGVzfQpjb25nX2FsbCA8LSBmYS5jb25ncnVlbmNlKHggPSBsaXN0KGVmYV91c19hZHVsdHMkbG9hZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZhX2doX2FkdWx0cyRsb2FkaW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmFfdGhfYWR1bHRzJGxvYWRpbmdzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmYV9jaF9hZHVsdHMkbG9hZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZhX3Z0X2FkdWx0cyRsb2FkaW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmFfdXNfY2hpbGRyZW4kbG9hZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZhX2doX2NoaWxkcmVuJGxvYWRpbmdzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVmYV90aF9jaGlsZHJlbiRsb2FkaW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZmFfY2hfY2hpbGRyZW4kbG9hZGluZ3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZhX3Z0X2NoaWxkcmVuJGxvYWRpbmdzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSA1KSAlPiUKICAjIGdldF91cHBlcl90cmlfZnVuKCkgJT4lCiAgZGF0YS5mcmFtZSgpICU+JQogIHJvd25hbWVzX3RvX2NvbHVtbigiZmFjdG9yX0EiKSAlPiUKICBnYXRoZXIoZmFjdG9yX0IsIGNvbmcsIC1mYWN0b3JfQSkgJT4lCiAgbGVmdF9qb2luKGJpbmRfcm93cyhmYWN0b3JfbmFtZXNfYWR1bHRzICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2FsbChmdW5zKHBhc3RlKC4sICJBIiwgc2VwID0gIl8iKSkpLAogICAgICAgICAgICAgICAgICAgICAgZmFjdG9yX25hbWVzX2NoaWxkcmVuICU+JQogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkEiLCBzZXAgPSAiXyIpKSkpKSAlPiUKICBsZWZ0X2pvaW4oYmluZF9yb3dzKGZhY3Rvcl9uYW1lc19hZHVsdHMgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkIiLCBzZXAgPSAiXyIpKSksCiAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JfbmFtZXNfY2hpbGRyZW4gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hbGwoZnVucyhwYXN0ZSguLCAiQiIsIHNlcCA9ICJfIikpKSkpCmBgYAoKYGBge3IgY29uZyBhbGwgcGFpcnMgZm9ybWF0fQojIG1ha2Ugd2lkZS1mb3JtIHZlcnNpb24gb2YgZGYKY29uZ19hbGxfdyA8LSBjb25nX2FsbCAlPiUKICBzZWxlY3QoZmFjdG9yX0EsIGZhY3Rvcl9CLCBjb25nKSAlPiUKICBzcHJlYWQoZmFjdG9yX0IsIGNvbmcpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiZmFjdG9yX0EiKQoKIyB0cmVhdCBzaW1pbGFyaXR5IG1hdHJpeCBhcyBpZiBpdCB3ZXJlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIGhjbHVzdApyb3cub3JkZXIgPC0gaGNsdXN0KGFzLmRpc3QoKDEgLSBjb25nX2FsbF93KS8yKSkkb3JkZXIKY29sLm9yZGVyIDwtIGhjbHVzdChhcy5kaXN0KHQoKDEgLSBjb25nX2FsbF93KS8yKSkpJG9yZGVyCgojIHJlLW9yZGVyIG1hdHJpeCBhY2NvcmluZyB0byBjbHVzdGVyaW5nCmNvbmdfYWxsX3cgPC0gY29uZ19hbGxfd1tyb3cub3JkZXIsIGNvbC5vcmRlcl0gCgojIGZvciBzb21lIHJlYXNvbiByZXNoYXBlMjo6bWVsdCgpIHdvcmtzIGJldHRlciB0aGFuIGN1cnJlbnQgdGlkeXZlcnNlIGZ1bmN0aW9ucy4uLgpjb25nX2FsbF9vcmRlcmVkIDwtIG1lbHQoYXMubWF0cml4KGNvbmdfYWxsX3cpKSAlPiUKICByZW5hbWUoZmFjdG9yX0Ffb3JkZXJlZCA9IFZhcjEsIAogICAgICAgICBmYWN0b3JfQl9vcmRlcmVkID0gVmFyMiwKICAgICAgICAgY29uZyA9IHZhbHVlKSAlPiUKICBtdXRhdGUoZmFjdG9yX0EgPSBhcy5jaGFyYWN0ZXIoZmFjdG9yX0Ffb3JkZXJlZCksCiAgICAgICAgIGZhY3Rvcl9CID0gYXMuY2hhcmFjdGVyKGZhY3Rvcl9CX29yZGVyZWQpKSAlPiUKICBmdWxsX2pvaW4oY29uZ19hbGwgJT4lIHNlbGVjdChjb250YWlucygiX0EiKSkgJT4lIGRpc3RpbmN0KCkpICU+JQogIGZ1bGxfam9pbihjb25nX2FsbCAlPiUgc2VsZWN0KGNvbnRhaW5zKCJfQiIpKSAlPiUgZGlzdGluY3QoKSkgJT4lCiAgbXV0YXRlKGxhYl9BID0gcGFzdGUocGFzdGUoY291bnRyeV9BLCBhZ2VfZ3JvdXBfQSksIGZhY3Rvcl9sYWJkZXNjcmlwdF9BLCBzZXAgPSAiLCAiKSwKICAgICAgICAgbGFiX0IgPSBwYXN0ZShwYXN0ZShjb3VudHJ5X0IsIGFnZV9ncm91cF9CKSwgZmFjdG9yX2xhYmRlc2NyaXB0X0IsIHNlcCA9ICIsICIpKQojIG11dGF0ZShzYW1wbGVfQSA9IHBhc3RlKGNvdW50cnlfQSwgYWdlX2dyb3VwX0EsIHNlcCA9ICIsICIpLAojICAgICAgICBzYW1wbGVfQiA9IHBhc3RlKGNvdW50cnlfQiwgYWdlX2dyb3VwX0IsIHNlcCA9ICIsICIpLAojICAgICAgICBsYWJfQSA9IHBhc3RlKHNhbXBsZV9BLCBmYWN0b3JfbGFiZGVzY3JpcHRfQSwgc2VwID0gIiAiKSwKIyAgICAgICAgbGFiX0IgPSBwYXN0ZShzYW1wbGVfQiwgZmFjdG9yX2xhYmRlc2NyaXB0X0IsIHNlcCA9ICIgIikpCmBgYAoKYGBge3IgY29uZyBhbGwgcGFpcnMgcGxvdCwgZmlnLndpZHRoID0gOS41LCBmaWcuYXNwID0gMC45fQojIEZJR1VSRSAyCmNvbmdfbG93ZXJfbGltIDwtIGlmZWxzZShtaW4oY29uZ19hbGxfb3JkZXJlZCRjb25nKSA+IC0wLjA1LCAtMC4wNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBtaW4oY29uZ19hbGxfb3JkZXJlZCRjb25nKSkKIyBjb25nX3Bsb3RfY29sb3JzIDwtIGMoInJlZDQiLCAiYmx1ZTQiLCAiZGFya29yY2hpZDQiLCAiYmxhY2siKQojIGNvbmdfcGxvdF9jb2xvcnMgPC0gYygiYmxhY2siLCAiYmxhY2siLCAiYmxhY2siLCAiYmxhY2siKQpjb25nX3Bsb3RfY29sb3JzIDwtIGMoInJlZDQiLCAicmVkNCIsICJyZWQ0IiwgImJsYWNrIikKCmNvbmdfYWxsX29yZGVyZWQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihsYWJfQSwgYXMubnVtZXJpYyhmYWN0b3JfQV9vcmRlcmVkKSksCiAgICAgICAgICAgICB5ID0gcmVvcmRlcihsYWJfQiwgYXMubnVtZXJpYyhkZXNjKGZhY3Rvcl9CX29yZGVyZWQpKSksCiAgICAgICAgICAgICBmaWxsID0gY29uZykpICsgCiAgZ2VvbV90aWxlKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmb3JtYXQocm91bmQoY29uZywgMiksIG5zbWFsbCA9IDIpLAogICAgICAgICAgICAgICAgY29sb3IgPSBjYXNlX3doZW4oY29uZyA+IDAuODUgfiAiYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZyA+IDAuNzUgfiAiYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25nID4gMC42NSB+ICJjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiZCIpKSwKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArCiAgIyBib2R5LWxpa2UgZmFjdG9ycwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IDUuNSwgeG1heCA9IDE1LjUsIHltaW4gPSAxNi41LCB5bWF4ID0gMjYuNSwKICAgICAgICAgICBjb2xvciA9IGNvbmdfcGxvdF9jb2xvcnNbMV0sIHNpemUgPSAxLjUsIGFscGhhID0gMCkgKwogICMgbWluZC1saWtlIGZhY3RvcnMKICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSAxNS41LCB4bWF4ID0gMjUuNSwgeW1pbiA9IDYuNSwgeW1heCA9IDE2LjUsCiAgICAgICAgICAgY29sb3IgPSBjb25nX3Bsb3RfY29sb3JzWzJdLCBzaXplID0gMS41LCBhbHBoYSA9IDApICsKICAjIGhlYXJ0LWxpa2UgZmFjdG9ycwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IDI1LjUsIHhtYXggPSAzMS41LCB5bWluID0gMC41LCB5bWF4ID0gNi41LAogICAgICAgICAgIGNvbG9yID0gY29uZ19wbG90X2NvbG9yc1szXSwgc2l6ZSA9IDEuNSwgYWxwaGEgPSAwKSArCiAgIyBzY2FsZV9maWxsX3ZpcmlkaXNfYyh0cmFucyA9IHNjYWxlczo6ZXhwX3RyYW5zKGJhc2UgPSBleHAoMSkpLAogICMgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhjb25nX2xvd2VyX2xpbSwgMSksIAogICMgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGNvbmdfbG93ZXJfbGltLCAxLCAwLjA1KSwKICAjICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZm9ybWF0KHNlcShjb25nX2xvd2VyX2xpbSwgMC44LCAwLjA1KSwgbnNtYWxsID0gMiksCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjg1ID0gbW9kZXJhdGUiLCAiMC45MCIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC45NSA9IGhpZ2giLCAiMS4wMCIpLAogICMgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gInZpcmlkaXMiLAogICMgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihiYXJoZWlnaHQgPSA0MCkpICsKICBzY2FsZV9maWxsX2dyYWRpZW50bigjdHJhbnMgPSBzY2FsZXM6OmV4cF90cmFucyhiYXNlID0gZXhwKDEpKSwKICAgIGxpbWl0cyA9IGMoY29uZ19sb3dlcl9saW0sIDEpLCAKICAgIGJyZWFrcyA9IHNlcShjb25nX2xvd2VyX2xpbSwgMSwgMC4wNSksCiAgICBsYWJlbHMgPSBjKGZvcm1hdChzZXEoY29uZ19sb3dlcl9saW0sIDAuOCwgMC4wNSksIG5zbWFsbCA9IDIpLAogICAgICAgICAgICAgICAiMC44NSA9IG1vZGVyYXRlIiwgIjAuOTAiLCAKICAgICAgICAgICAgICAgIjAuOTUgPSBoaWdoIiwgIjEuMDAiKSwKICAgIGNvbG9ycyA9IHZpcmlkaXNMaXRlOjp2aXJpZGlzKDYpLAogICAgdmFsdWVzID0gYygwLCAwLjY1LCAwLjc1LCAwLjg1LCAwLjk1LCAxKSwKICAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIoYmFyaGVpZ2h0ID0gNDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgImJsYWNrIiwgImJsYWNrIiwgImdyYXk2MCIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICAjIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxLAogICAgICBhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMSwKICAgICAgc2l6ZSA9IHNpemVfZnVuKGNvbmdfYWxsX29yZGVyZWQkbGFiX0EsIHNpemVzID0gYygyMCwgMTQpKSwKICAgICAgY29sb3IgPSBjb2xvcl9mdW4oY29uZ19hbGxfb3JkZXJlZCRsYWJfQSwgY29sb3JfbGlzdCA9IGNvbmdfcGxvdF9jb2xvcnMpLAogICAgICBmYWNlICA9IGZhY2VfZnVuKGNvbmdfYWxsX29yZGVyZWQkbGFiX0EpKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gcmV2KHNpemVfZnVuKGNvbmdfYWxsX29yZGVyZWQkbGFiX0EsIHNpemVzID0gYygyMCwgMTQpKSksCiAgICAgIGNvbG9yID0gcmV2KGNvbG9yX2Z1bihjb25nX2FsbF9vcmRlcmVkJGxhYl9BLCBjb2xvcl9saXN0ID0gY29uZ19wbG90X2NvbG9ycykpLAogICAgICBmYWNlICA9IHJldihmYWNlX2Z1bihjb25nX2FsbF9vcmRlcmVkJGxhYl9BKSkpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAyMCksCiAgICAjIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNSksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoCiAgICAgIHNpemUgPSBzaXplX2Z1bihjb25nX2FsbF9vcmRlcmVkJGxhYl9BLCBzaXplcyA9IGMoMS41LCAwLjUpKSwKICAgICAgY29sb3IgPSBjb2xvcl9mdW4oY29uZ19hbGxfb3JkZXJlZCRsYWJfQSwgY29sb3JfbGlzdCA9IGNvbmdfcGxvdF9jb2xvcnMpKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfbGluZSgKICAgICAgc2l6ZSA9IHJldihzaXplX2Z1bihjb25nX2FsbF9vcmRlcmVkJGxhYl9BLCBzaXplcyA9IGMoMS41LCAwLjUpKSksCiAgICAgIGNvbG9yID0gcmV2KGNvbG9yX2Z1bihjb25nX2FsbF9vcmRlcmVkJGxhYl9BLCBjb2xvcl9saXN0ID0gY29uZ19wbG90X2NvbG9ycykpKSwKICAgIGF4aXMudGlja3MubGVuZ3RoID0gdW5pdCgwLjI1LCAiY20iKSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gZXhwcmVzc2lvbihpdGFsaWMocltjXSkpKQpnZ3NhdmUoIi4uL2ZpZ3VyZXMvZmlnMDJfb3J0aG9nb25hbC5wbmciKQpgYGAKCiMjIEphY2NhcmQgU2ltaWxhcml0eQoKYGBge3IgamFjY2FyZCBhbGwgc2FtcGxlc30Kc3Ryb25nX2xvYWRfYWxsIDwtIGxvYWRpbmdzX2FkdWx0cyAlPiUKICBiaW5kX3Jvd3MobG9hZGluZ3NfY2hpbGRyZW4pICU+JQogIHNlbGVjdChjb3VudHJ5LCBhZ2VfZ3JvdXAsIGZhY3RvciwgY2FwYWNpdHksIGxvYWRpbmcpICU+JQogIG11dGF0ZShzdHJvbmdfbG9hZCA9IGlmZWxzZShsb2FkaW5nID49IDAuNSwgMSwgMCkpICU+JQogIHNlbGVjdCgtbG9hZGluZykKCmNyb3NzX2xvYWRfYWxsIDwtIHN0cm9uZ19sb2FkX2FsbCAlPiUKICBmaWx0ZXIoc3Ryb25nX2xvYWQgPT0gMSkgJT4lCiAgY291bnQoY291bnRyeSwgYWdlX2dyb3VwLCBjYXBhY2l0eSwgc3Ryb25nX2xvYWQpICU+JQogIGZpbHRlcihuID4gMSkgJT4lCiAgbXV0YXRlKGNyb3NzX2xvYWQgPSBUKSAlPiUKICBzZWxlY3QoY291bnRyeSwgYWdlX2dyb3VwLCBjYXBhY2l0eSwgY3Jvc3NfbG9hZCkKCnN0cm9uZ19ub25jcm9zc19sb2FkX2FsbCA8LSBzdHJvbmdfbG9hZF9hbGwgJT4lCiAgbGVmdF9qb2luKGNyb3NzX2xvYWRfYWxsKSAlPiUKICBmaWx0ZXIoaXMubmEoY3Jvc3NfbG9hZCkpCgpqYWNjYXJkX2FsbCA8LSBzdHJvbmdfbm9uY3Jvc3NfbG9hZF9hbGwgJT4lCiAgc2VsZWN0KGZhY3RvciwgY2FwYWNpdHksIHN0cm9uZ19sb2FkKSAlPiUKICBzcHJlYWQoZmFjdG9yLCBzdHJvbmdfbG9hZCkgJT4lCiAgY29sdW1uX3RvX3Jvd25hbWVzKCJjYXBhY2l0eSIpICU+JQogIHQoKSAlPiUKICBkaXN0KG1ldGhvZCA9ICJiaW5hcnkiLCBkaWFnID0gVCwgdXBwZXIgPSBUKSAlPiUKICBhcy5tYXRyaXgoKSAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKCJmYWN0b3JfQSIpICU+JQogIGdhdGhlcihmYWN0b3JfQiwgamFjY2FyZCwgLWZhY3Rvcl9BKSAlPiUKICAjIGNvbXB1dGUgc2ltaWxhcml0eSBpbmRleCBpbnN0ZWFkIG9mIGRpc3RhbmNlCiAgbXV0YXRlKGphY2NhcmQgPSAxIC0gamFjY2FyZCkgJT4lCiAgbGVmdF9qb2luKGJpbmRfcm93cyhmYWN0b3JfbmFtZXNfYWR1bHRzICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgcmVuYW1lX2FsbChmdW5zKHBhc3RlKC4sICJBIiwgc2VwID0gIl8iKSkpLAogICAgICAgICAgICAgICAgICAgICAgZmFjdG9yX25hbWVzX2NoaWxkcmVuICU+JQogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkEiLCBzZXAgPSAiXyIpKSkpKSAlPiUKICBsZWZ0X2pvaW4oYmluZF9yb3dzKGZhY3Rvcl9uYW1lc19hZHVsdHMgJT4lIAogICAgICAgICAgICAgICAgICAgICAgICByZW5hbWVfYWxsKGZ1bnMocGFzdGUoLiwgIkIiLCBzZXAgPSAiXyIpKSksCiAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JfbmFtZXNfY2hpbGRyZW4gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZV9hbGwoZnVucyhwYXN0ZSguLCAiQiIsIHNlcCA9ICJfIikpKSkpCmBgYAoKYGBge3IgamFjY2FyZCBhbGwgcGFpcnMgZm9ybWF0fQojIG1ha2Ugd2lkZS1mb3JtIHZlcnNpb24gb2YgZGYKamFjY2FyZF9hbGxfdyA8LSBqYWNjYXJkX2FsbCAlPiUKICBzZWxlY3QoZmFjdG9yX0EsIGZhY3Rvcl9CLCBqYWNjYXJkKSAlPiUKICBzcHJlYWQoZmFjdG9yX0IsIGphY2NhcmQpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiZmFjdG9yX0EiKQoKIyB0cmVhdCBkaXN0YW5jZSBtYXRyaXggYXMgaWYgaXQgd2VyZSB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciBoY2x1c3QKcm93Lm9yZGVyIDwtIGhjbHVzdChhcy5kaXN0KCgxIC0gamFjY2FyZF9hbGxfdykvMikpJG9yZGVyCmNvbC5vcmRlciA8LSBoY2x1c3QoYXMuZGlzdCh0KCgxIC0gamFjY2FyZF9hbGxfdykvMikpKSRvcmRlcgoKIyByZS1vcmRlciBtYXRyaXggYWNjb3JpbmcgdG8gY2x1c3RlcmluZwpqYWNjYXJkX2FsbF93IDwtIGphY2NhcmRfYWxsX3dbcm93Lm9yZGVyLCBjb2wub3JkZXJdIAoKIyBmb3Igc29tZSByZWFzb24gcmVzaGFwZTI6Om1lbHQoKSB3b3JrcyBiZXR0ZXIgdGhhbiBjdXJyZW50IHRpZHl2ZXJzZSBmdW5jdGlvbnMuLi4KamFjY2FyZF9hbGxfb3JkZXJlZCA8LSBtZWx0KGFzLm1hdHJpeChqYWNjYXJkX2FsbF93KSkgJT4lCiAgcmVuYW1lKGZhY3Rvcl9BX29yZGVyZWQgPSBWYXIxLCAKICAgICAgICAgZmFjdG9yX0Jfb3JkZXJlZCA9IFZhcjIsCiAgICAgICAgIGphY2NhcmQgPSB2YWx1ZSkgJT4lCiAgbXV0YXRlKGZhY3Rvcl9BID0gYXMuY2hhcmFjdGVyKGZhY3Rvcl9BX29yZGVyZWQpLAogICAgICAgICBmYWN0b3JfQiA9IGFzLmNoYXJhY3RlcihmYWN0b3JfQl9vcmRlcmVkKSkgJT4lCiAgZnVsbF9qb2luKGphY2NhcmRfYWxsICU+JSBzZWxlY3QoY29udGFpbnMoIl9BIikpICU+JSBkaXN0aW5jdCgpKSAlPiUKICBmdWxsX2pvaW4oamFjY2FyZF9hbGwgJT4lIHNlbGVjdChjb250YWlucygiX0IiKSkgJT4lIGRpc3RpbmN0KCkpICU+JQogIG11dGF0ZShsYWJfQSA9IHBhc3RlKHBhc3RlKGNvdW50cnlfQSwgYWdlX2dyb3VwX0EpLCBmYWN0b3JfbGFiZGVzY3JpcHRfQSwgc2VwID0gIiwgIiksCiAgICAgICAgIGxhYl9CID0gcGFzdGUocGFzdGUoY291bnRyeV9CLCBhZ2VfZ3JvdXBfQiksIGZhY3Rvcl9sYWJkZXNjcmlwdF9CLCBzZXAgPSAiLCAiKSkKIyBtdXRhdGUoc2FtcGxlX0EgPSBwYXN0ZShjb3VudHJ5X0EsIGFnZV9ncm91cF9BLCBzZXAgPSAiLCAiKSwKIyAgICAgICAgc2FtcGxlX0IgPSBwYXN0ZShjb3VudHJ5X0IsIGFnZV9ncm91cF9CLCBzZXAgPSAiLCAiKSwKIyAgICAgICAgbGFiX0EgPSBwYXN0ZShzYW1wbGVfQSwgZmFjdG9yX2xhYmRlc2NyaXB0X0EsIHNlcCA9ICIgIiksCiMgICAgICAgIGxhYl9CID0gcGFzdGUoc2FtcGxlX0IsIGZhY3Rvcl9sYWJkZXNjcmlwdF9CLCBzZXAgPSAiICIpKQpgYGAKCmBgYHtyIGphY2NhcmQgYWxsIHBhaXJzIHBsb3QsIGZpZy53aWR0aCA9IDkuNSwgZmlnLmFzcCA9IDAuOX0KIyBGSUdVUkUgMiBlcXVpdmFsZW50CmphY2NhcmRfbG93ZXJfbGltIDwtIGlmZWxzZShtaW4oamFjY2FyZF9hbGxfb3JkZXJlZCRqYWNjYXJkKSA+IDAsIDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgbWluKGphY2NhcmRfYWxsX29yZGVyZWQkamFjY2FyZCkpCiMgamFjY2FyZF9wbG90X2NvbG9ycyA8LSBjKCJyZWQ0IiwgImJsdWU0IiwgImRhcmtvcmNoaWQ0IiwgImJsYWNrIikKIyBqYWNjYXJkX3Bsb3RfY29sb3JzIDwtIGMoImJsYWNrIiwgImJsYWNrIiwgImJsYWNrIiwgImJsYWNrIikKamFjY2FyZF9wbG90X2NvbG9ycyA8LSBjKCJyZWQ0IiwgInJlZDQiLCAicmVkNCIsICJibGFjayIpCgpqYWNjYXJkX2FsbF9vcmRlcmVkICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIobGFiX0EsIGFzLm51bWVyaWMoZmFjdG9yX0Ffb3JkZXJlZCkpLAogICAgICAgICAgICAgeSA9IHJlb3JkZXIobGFiX0IsIGFzLm51bWVyaWMoZGVzYyhmYWN0b3JfQl9vcmRlcmVkKSkpLAogICAgICAgICAgICAgZmlsbCA9IGphY2NhcmQpKSArIAogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY2FzZV93aGVuKAogICAgIyBqYWNjYXJkICVpbiUgYygwLCAxKSB+IGZvcm1hdChyb3VuZChqYWNjYXJkLCAwKSwgbnNtYWxsID0gMCksCiAgICBUUlVFIH4gZm9ybWF0KHJvdW5kKGphY2NhcmQsIDIpLCBuc21hbGwgPSAyKSksCiAgICBjb2xvciA9IGNhc2Vfd2hlbihqYWNjYXJkID49IDAuNzUgfiAiYSIsIAogICAgICAgICAgICAgICAgICAgICAgamFjY2FyZCA+PSAwLjUgfiAiYiIsCiAgICAgICAgICAgICAgICAgICAgICBqYWNjYXJkID49IDAuMjUgfiAiYyIsCiAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gImQiKSksCiAgICBzaG93LmxlZ2VuZCA9IEYpICsKICAjIG1pbmQtbGlrZSBhbmQgb3RoZXIgZmFjdG9ycwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IDAuNSwgeG1heCA9IDE0LjUsIHltaW4gPSAxNy41LCB5bWF4ID0gMzEuNSwKICAgICAgICAgICBjb2xvciA9IGphY2NhcmRfcGxvdF9jb2xvcnNbMl0sIHNpemUgPSAxLjUsIGFscGhhID0gMCkgKwogICMgYm9keS1saWtlIGZhY3RvcnMKICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSAxNC41LCB4bWF4ID0gMjQuNSwgeW1pbiA9IDcuNSwgeW1heCA9IDE3LjUsCiAgICAgICAgICAgY29sb3IgPSBqYWNjYXJkX3Bsb3RfY29sb3JzWzFdLCBzaXplID0gMS41LCBhbHBoYSA9IDApICsKICAjIGhlYXJ0LWxpa2UgZmFjdG9ycwogIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IDI0LjUsIHhtYXggPSAzMS41LCB5bWluID0gMC41LCB5bWF4ID0gNy41LAogICAgICAgICAgIGNvbG9yID0gamFjY2FyZF9wbG90X2NvbG9yc1szXSwgc2l6ZSA9IDEuNSwgYWxwaGEgPSAwKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoI3RyYW5zID0gc2NhbGVzOjpleHBfdHJhbnMoYmFzZSA9IGV4cCgxKSksCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhqYWNjYXJkX2xvd2VyX2xpbSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGphY2NhcmRfbG93ZXJfbGltLCAxLCAwLjA1KSwKICAgICAgICAgICAgICAgICAgICAgICAjIGxhYmVscyA9IGMoZm9ybWF0KHNlcShqYWNjYXJkX2xvd2VyX2xpbSwgMC44LCAwLjA1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgICAgICAgICAgICAgICBuc21hbGwgPSAyKSwKICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgIjAuODUgPSBtb2RlcmF0ZSIsICIwLjkwIiwKICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgICAgICAgIjAuOTUgPSBoaWdoIiwgIjEuMDAiKSwKICAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAidmlyaWRpcyIsIAogICAgICAgICAgICAgICAgICAgICAgICMgZGlyZWN0aW9uID0gLTEsCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcihiYXJoZWlnaHQgPSA0MCkpICsKICAjIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKCN0cmFucyA9IHNjYWxlczo6ZXhwX3RyYW5zKGJhc2UgPSBleHAoMSkpLAogICMgICBsaW1pdHMgPSBjKGphY2NhcmRfbG93ZXJfbGltLCAxKSwgCiAgIyAgIGJyZWFrcyA9IHNlcShqYWNjYXJkX2xvd2VyX2xpbSwgMSwgMC4wNSksCiAgIyAgIGxhYmVscyA9IGMoZm9ybWF0KHNlcShqYWNjYXJkX2xvd2VyX2xpbSwgMC44LCAwLjA1KSwgbnNtYWxsID0gMiksCiAgIyAgICAgICAgICAgICAgIjAuODUgPSBtb2RlcmF0ZSIsICIwLjkwIiwgCiAgIyAgICAgICAgICAgICAgIjAuOTUgPSBoaWdoIiwgIjEuMDAiKSwKICAjICAgY29sb3JzID0gdmlyaWRpc0xpdGU6OnZpcmlkaXMoNiksCiAgIyAgIHZhbHVlcyA9IGMoMCwgMC42NSwgMC43NSwgMC44NSwgMC45NSwgMSksCiAgIyAgIGd1aWRlID0gZ3VpZGVfY29sb3JiYXIoYmFyaGVpZ2h0ID0gNDApKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgImJsYWNrIiwgImJsYWNrIiwgImdyYXk2MCIpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KAogICAgICAjIGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxLAogICAgICBhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMSwKICAgICAgc2l6ZSA9IHNpemVfZnVuKGphY2NhcmRfYWxsX29yZGVyZWQkbGFiX0EsIHNpemVzID0gYygyMCwgMTQpKSwKICAgICAgY29sb3IgPSBjb2xvcl9mdW4oamFjY2FyZF9hbGxfb3JkZXJlZCRsYWJfQSwgY29sb3JfbGlzdCA9IGphY2NhcmRfcGxvdF9jb2xvcnMpLAogICAgICBmYWNlICA9IGZhY2VfZnVuKGphY2NhcmRfYWxsX29yZGVyZWQkbGFiX0EpKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KAogICAgICBzaXplID0gcmV2KHNpemVfZnVuKGphY2NhcmRfYWxsX29yZGVyZWQkbGFiX0EsIHNpemVzID0gYygyMCwgMTQpKSksCiAgICAgIGNvbG9yID0gcmV2KGNvbG9yX2Z1bihqYWNjYXJkX2FsbF9vcmRlcmVkJGxhYl9BLCBjb2xvcl9saXN0ID0gamFjY2FyZF9wbG90X2NvbG9ycykpLAogICAgICBmYWNlICA9IHJldihmYWNlX2Z1bihqYWNjYXJkX2FsbF9vcmRlcmVkJGxhYl9BKSkpLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAyMCksCiAgICAjIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNSksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoCiAgICAgIHNpemUgPSBzaXplX2Z1bihqYWNjYXJkX2FsbF9vcmRlcmVkJGxhYl9BLCBzaXplcyA9IGMoMS41LCAwLjUpKSwKICAgICAgY29sb3IgPSBjb2xvcl9mdW4oamFjY2FyZF9hbGxfb3JkZXJlZCRsYWJfQSwgY29sb3JfbGlzdCA9IGphY2NhcmRfcGxvdF9jb2xvcnMpKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfbGluZSgKICAgICAgc2l6ZSA9IHJldihzaXplX2Z1bihqYWNjYXJkX2FsbF9vcmRlcmVkJGxhYl9BLCBzaXplcyA9IGMoMS41LCAwLjUpKSksCiAgICAgIGNvbG9yID0gcmV2KGNvbG9yX2Z1bihqYWNjYXJkX2FsbF9vcmRlcmVkJGxhYl9BLCBjb2xvcl9saXN0ID0gamFjY2FyZF9wbG90X2NvbG9ycykpKSwKICAgIGF4aXMudGlja3MubGVuZ3RoID0gdW5pdCgwLjI1LCAiY20iKSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCBmaWxsID0gIkphY2NhcmRcbnNpbWlsYXJpdHkiKQpnZ3NhdmUoIi4uL2ZpZ3VyZXMvZmlnMDJfb3J0aG9nb25hbF9qYWNjYXJkLnBuZyIpCmBgYAoKIyMgRGV2ZWxvcG1lbnRhbCBjb21wYXJpc29ucwoKYGBge3IgZGV2IGNvbXAgYWxsIHNpdGVzLCBmaWcud2lkdGggPSA0LCBmaWcuYXNwID0gMS4yfQojIEZJR1VSRSBTNSwgRklHVVJFIFM2LCBGSUdVUkUgUzcsIEZJR1VSRSBTOCwgRklHVVJFIFM5CnBsb3RfZ3JpZChoZWF0bWFwX2NvbXBfZnVuKAogIGVmYV9saXN0ID0gbGlzdChlZmFfdXNfYWR1bHRzLCBlZmFfdXNfY2hpbGRyZW4pLCBwYWRkaW5nID0gRiksCiAgZGV2X2NvbmdfcGxvdF9mdW4oY29uZ19kZl9jaGlsZHJlbiwgd2hpY2hfY291bnRyeSA9ICJVUyIsIHBhZGRpbmcgPSBUKSwKICBuY29sID0gMSwgcmVsX2hlaWdodHMgPSBjKDIsIDEuNSksIGxhYmVscyA9ICJBVVRPIikKZ2dzYXZlKCIuLi9maWd1cmVzL2ZpZ1MwNV9vcnRob2dvbmFsLnBuZyIpCgpwbG90X2dyaWQoaGVhdG1hcF9jb21wX2Z1bigKICBlZmFfbGlzdCA9IGxpc3QoZWZhX2doX2FkdWx0cywgZWZhX2doX2NoaWxkcmVuKSwgcGFkZGluZyA9IEYpLAogIGRldl9jb25nX3Bsb3RfZnVuKGNvbmdfZGZfY2hpbGRyZW4sIHdoaWNoX2NvdW50cnkgPSAiR2hhbmEiLCBwYWRkaW5nID0gVCksCiAgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYygyLCAxLjUpLCBsYWJlbHMgPSAiQVVUTyIpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWdTMDZfb3J0aG9nb25hbC5wbmciKQoKcGxvdF9ncmlkKGhlYXRtYXBfY29tcF9mdW4oCiAgZWZhX2xpc3QgPSBsaXN0KGVmYV90aF9hZHVsdHMsIGVmYV90aF9jaGlsZHJlbiksIHBhZGRpbmcgPSBGKSwKICBkZXZfY29uZ19wbG90X2Z1bihjb25nX2RmX2NoaWxkcmVuLCB3aGljaF9jb3VudHJ5ID0gIlRoYWlsYW5kIiwgcGFkZGluZyA9IFQpLAogIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoMiwgMS41KSwgbGFiZWxzID0gIkFVVE8iKQpnZ3NhdmUoIi4uL2ZpZ3VyZXMvZmlnUzA3X29ydGhvZ29uYWwucG5nIikKCnBsb3RfZ3JpZChoZWF0bWFwX2NvbXBfZnVuKAogIGVmYV9saXN0ID0gbGlzdChlZmFfY2hfYWR1bHRzLCBlZmFfY2hfY2hpbGRyZW4pLCBwYWRkaW5nID0gRiksCiAgZGV2X2NvbmdfcGxvdF9mdW4oY29uZ19kZl9jaGlsZHJlbiwgd2hpY2hfY291bnRyeSA9ICJDaGluYSIsIHBhZGRpbmcgPSBUKSwKICBuY29sID0gMSwgcmVsX2hlaWdodHMgPSBjKDIsIDEuNSksIGxhYmVscyA9ICJBVVRPIikKZ2dzYXZlKCIuLi9maWd1cmVzL2ZpZ1MwOF9vcnRob2dvbmFsLnBuZyIpCgpwbG90X2dyaWQoaGVhdG1hcF9jb21wX2Z1bigKICBlZmFfbGlzdCA9IGxpc3QoZWZhX3Z0X2FkdWx0cywgZWZhX3Z0X2NoaWxkcmVuKSwgcGFkZGluZyA9IEYpLAogIGRldl9jb25nX3Bsb3RfZnVuKGNvbmdfZGZfY2hpbGRyZW4sIHdoaWNoX2NvdW50cnkgPSAiVmFudWF0dSIsIHBhZGRpbmcgPSBUKSwKICBuY29sID0gMSwgcmVsX2hlaWdodHMgPSBjKDIsIDEuNSksIGxhYmVscyA9ICJBVVRPIikKZ2dzYXZlKCIuLi9maWd1cmVzL2ZpZ1MwOV9vcnRob2dvbmFsLnBuZyIpCmBgYAoKYGBge3IgbG9hZGluZ3MgYWxsIHNhbXBsZXMsIGZpZy53aWR0aCA9IDYuNSwgZmlnLmFzcCA9IDAuNn0KIyBGSUdVUkUgMSwgdmVyc2lvbiAxCmhlYXRtYXBfY29tcF9mdW4obGlzdChlZmFfdXNfYWR1bHRzLCBlZmFfZ2hfYWR1bHRzLCBlZmFfdGhfYWR1bHRzLCAKICAgICAgICAgICAgICAgICAgICAgIGVmYV9jaF9hZHVsdHMsIGVmYV92dF9hZHVsdHMsIAogICAgICAgICAgICAgICAgICAgICAgZWZhX3VzX2NoaWxkcmVuLCBlZmFfZ2hfY2hpbGRyZW4sIGVmYV90aF9jaGlsZHJlbiwgCiAgICAgICAgICAgICAgICAgICAgICBlZmFfY2hfY2hpbGRyZW4sIGVmYV92dF9jaGlsZHJlbiksIAogICAgICAgICAgICAgICAgIGZhY2V0X29yZGVyX3ZhcnMgPSBjKCJhZ2VfZ3JvdXAiLCAiY291bnRyeSIsICJmbnVtIiksCiAgICAgICAgICAgICAgICAgZmFjZXRfbGFiX3NwbGl0ID0gVCkgKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoYyhyZXAoMC4yLCA0KSwgMSwgcmVwKDAuMiwgNCkpLCAibGluZSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvcmJhcihiYXJ3aWR0aCA9IDMwLCBiYXJoZWlnaHQgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiRmFjdG9yIGxvYWRpbmciLCB0aXRsZS52anVzdCA9IDEpKQpnZ3NhdmUoIi4uL2ZpZ3VyZXMvZmlnMDF2MV9vcnRob2dvbmFsLnBuZyIpCmBgYAoKYGBge3IgZG9taW5hbnQgZmFjdG9yLCBmaWcud2lkdGggPSA2LjUsIGZpZy5hc3AgPSAwLjYsIGluY2x1ZGUgPSBGfQojIGhpZ2hsaWdodGluZyBkb21pbmFudCBmYWN0b3IgKGlnbm9yaW5nIGNyb3NzLWxvYWRpbmdzID4gMC4wNSkKbG9hZGluZ3NfYWxsIDwtIGxvYWRpbmdzX2FkdWx0cyAlPiUKICBzZWxlY3QoLWNvbnRhaW5zKCJvcmQiKSkgJT4lCiAgZnVsbF9qb2luKGxvYWRpbmdzX2NoaWxkcmVuICU+JQogICAgICAgICAgICAgIHNlbGVjdCgtY29udGFpbnMoIm9yZCIpKSkKCmRvbV9mYWN0b3JzX2FsbCA8LSBsb2FkaW5nc19hbGwgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgYWdlX2dyb3VwLCBjYXBhY2l0eSkgJT4lIAogIHRvcF9uKDEsIGFicyhsb2FkaW5nKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChjb3VudHJ5LCBhZ2VfZ3JvdXAsIGNhcGFjaXR5LCBmYWN0b3IsIGxvYWRpbmcpICU+JQogIHJlbmFtZShkb21fZmFjdG9yID0gZmFjdG9yLAogICAgICAgICBkb21fbG9hZGluZyA9IGxvYWRpbmcpCgpyZWN0X2RmIDwtIGxvYWRpbmdzX2FsbCAlPiUKICBmdWxsX2pvaW4oZG9tX2ZhY3RvcnNfYWxsKSAlPiUKICBtdXRhdGUoZm51bSA9IGdzdWIoIi4qX0YiLCAiRiIsIGZhY3RvcikpICU+JQogIHNlbGVjdCgtc3RhcnRzX3dpdGgoImZhY3RvciIpKSAlPiUKICBzcHJlYWQoZm51bSwgbG9hZGluZykgJT4lCiAgbXV0YXRlKGRpZmYxID0gYWJzKGRvbV9sb2FkaW5nKSAtIGFicyhGMSksCiAgICAgICAgIGRpZmYyID0gYWJzKGRvbV9sb2FkaW5nKSAtIGFicyhGMiksCiAgICAgICAgIGRpZmYzID0gYWJzKGRvbV9sb2FkaW5nKSAtIGFicyhGMyksCiAgICAgICAgIGRpZmY0ID0gYWJzKGRvbV9sb2FkaW5nKSAtIGFicyhGNCkpICU+JQogIHNlbGVjdCgtYyhkb21fbG9hZGluZywgc3RhcnRzX3dpdGgoIkYiKSkpICU+JQogIGdhdGhlcih3aGljaF9kaWZmLCBkaWZmLCBzdGFydHNfd2l0aCgiZGlmZiIpKSAlPiUKICBmaWx0ZXIoZGlmZiAhPSAwLCAhaXMubmEoZGlmZikpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGFnZV9ncm91cCwgY2FwYWNpdHkpICU+JQogIHRvcF9uKC0xLCBkaWZmKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFueV9zbWFsbCA9IGRpZmYgPCAwLjA1KSAlPiUKICByZW5hbWUoZmFjdG9yID0gZG9tX2ZhY3RvcikgJT4lCiAgbGVmdF9qb2luKGZ1bGxfam9pbihmYWN0b3JfbmFtZXNfYWR1bHRzLCBmYWN0b3JfbmFtZXNfY2hpbGRyZW4pKQoKIyBhbmFsb2cgdG8gRklHVVJFIDEKdGVtcF9jYXBfb3JkZXIgPC0gZmEuc29ydChlZmFfdXNfYWR1bHRzKSRsb2FkaW5nc1tdICU+JSByb3duYW1lcygpICU+JSByZXYoKQoKZ2dwbG90KHJlY3RfZGYgJT4lCiAgICAgICAgIGZpbHRlcighaXMubmEoYW55X3NtYWxsKSkgJT4lCiAgICAgICAgIG11dGF0ZShjYXBhY2l0eSA9IGZhY3RvcihjYXBhY2l0eSwgbGV2ZWxzID0gdGVtcF9jYXBfb3JkZXIpKSwKICAgICAgIGFlcyh4ID0gZmFjdG9yX2xhYmRlc2NyaXB0LCAKICAgICAgICAgICB5ID0gY2FwYWNpdHksIAogICAgICAgICAgIGZpbGwgPSBhbnlfc21hbGwpKSArCiAgZmFjZXRfZ3JpZCh+IGludGVyYWN0aW9uKGNvdW50cnksIGFnZV9ncm91cCksIHNwYWNlID0gImZyZWUiLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX3RpbGUoKSArCiAgdGhlbWUocGFuZWwuc3BhY2luZy54ID0gdW5pdChjKHJlcCgwLjIsIDQpLCAxLCByZXAoMC4yLCA0KSksICJsaW5lIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQojIGdnc2F2ZSgiLi4vZmlndXJlcy9maWcwMXYyX29ydGhvZ29uYWwucG5nIikKYGBgCgpgYGB7ciBsb2FkaW5ncyBhbGwgc2FtcGxlcyB2MiwgZmlnLndpZHRoID0gNi41LCBmaWcuYXNwID0gMC42fQojIEZJR1VSRSAxLCB2ZXJzaW9uIDIgKGluY2x1ZGVkIGluIG1haW4gdGV4dCkKbG9hZGluZ3NfYWR1bHRzICU+JQogIGJpbmRfcm93cyhsb2FkaW5nc19jaGlsZHJlbikgJT4lCiAgIyBzZWxlY3QoLWNvbnRhaW5zKCJfb3JkIikpICU+JQogIG11dGF0ZShmYWN0b3JfYmhtID0gY2FzZV93aGVuKAogICAgZ3JlcGwoImJvZHkiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdCkpIH4gIkJPRFktbGlrZSBmYWN0b3JzIiwKICAgIGdyZXBsKCJtaW5kIiwgdG9sb3dlcihmYWN0b3JfZGVzY3JpcHQpKSB+ICJNSU5ELWxpa2UgZmFjdG9ycyIsCiAgICBncmVwbCgiaGVhcnQiLCB0b2xvd2VyKGZhY3Rvcl9kZXNjcmlwdCkpIH4gIkhFQVJULWxpa2UgZmFjdG9ycyIsCiAgICBUUlVFIH4gIk90aGVyIikpICU+JQogIGxlZnRfam9pbihzdHJvbmdfbm9uY3Jvc3NfbG9hZF9hbGwgJT4lIAogICAgICAgICAgICAgIHNlbGVjdChmYWN0b3IsIGNhcGFjaXR5LCBzdHJvbmdfbG9hZCwgY3Jvc3NfbG9hZCkpICU+JQogIG11dGF0ZShmb250X2ZhY2UgPSBjYXNlX3doZW4oCiAgICBzdHJvbmdfbG9hZCA9PSAxICYgaXMubmEoY3Jvc3NfbG9hZCkgfiAiYm9sZCIsCiAgICBUUlVFIH4gInBsYWluIikpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIocGFzdGUoZ3N1YigiRmFjdG9yICIsICJGIiwgZmFjdG9yX25hbWUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3Rvcl9kZXNjcmlwdCwgc2VwID0gIjogIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyhjb3VudHJ5KSksIAogICAgICAgICAgICAgeSA9IHJlb3JkZXIoY2FwYWNpdHlfb3JkX3VzLCBkZXNjKGNhcGFjaXR5X29yZF91cykpLAogICAgICAgICAgICAgZmlsbCA9IGxvYWRpbmcpKSArCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhmYWN0b3JfYmhtLCBhZ2VfZ3JvdXApLCAKICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2UgPSAiZnJlZSIpICsKICBnZW9tX3RpbGUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGZvcm1hdChyb3VuZChsb2FkaW5nLCAyKSwgbnNtYWxsID0gMiksIAogICAgICAgICAgICAgICAgZm9udGZhY2UgPSBmb250X2ZhY2UpLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiUmRZbEJ1IiwgbGltaXRzID0gYygtMSwgMSkpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpLAogICAgICAgIHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoYygwLjIsIDEsIDAuMiwgMSwgMC4yLCAxLCAwLjIpLCAibGluZSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvcmJhcihiYXJ3aWR0aCA9IDMwLCBiYXJoZWlnaHQgPSAwLjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiRmFjdG9yIGxvYWRpbmciLCB0aXRsZS52anVzdCA9IDEpKQogICMgc2VsZWN0KGNvdW50cnksIGNhcGFjaXR5LCBsb2FkaW5nKSAlPiUKICAjIG11dGF0ZShsb2FkaW5nID0gcm91bmQobG9hZGluZywgMikpICU+JQogICMgc3ByZWFkKGNvdW50cnksIGxvYWRpbmcpCmdnc2F2ZSgiLi4vZmlndXJlcy9maWcwMXYyX29ydGhvZ29uYWwucG5nIikKYGBgCgojIyBWYXJpYW5jZSBhY2NvdW50ZWQgZm9yCgpgYGB7cn0KVmFjY291bnRlZF9mdW4gPC0gZnVuY3Rpb24oZWZhX25hbWUpIHsKICBjb3VudHJ5IDwtIGdzdWIoImVmYV8iLCAiIiwgZWZhX25hbWUpCiAgY291bnRyeSA8LSBnc3ViKCJfLiokIiwgIiIsIGNvdW50cnkpCiAgYWdlX2dyb3VwIDwtIGNhc2Vfd2hlbihncmVwbCgiYWR1bHQiLCBlZmFfbmFtZSkgfiAiYWR1bHRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJjaGlsZCIsIGVmYV9uYW1lKSB+ICJjaGlsZHJlbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXykKICAKICBlZmEgPC0gZ2V0KGVmYV9uYW1lKQogIHJlcyA8LSBlZmEkVmFjY291bnRlZCAlPiUKICAgIGRhdGEuZnJhbWUoKSAlPiUKICAgIHJvd25hbWVzX3RvX2NvbHVtbigibWV0cmljIikgJT4lCiAgICBtdXRhdGUoY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInVzIiwgImdoIiwgInRoIiwgImNoIiwgInZ0IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBsZXZlbHNfY291bnRyeSksCiAgICAgICAgICAgYWdlX2dyb3VwID0gZmFjdG9yKGFnZV9ncm91cCwgbGV2ZWxzID0gYygiYWR1bHRzIiwgImNoaWxkcmVuIikpKQogIAogIHJldHVybihyZXMpCn0KYGBgCgpgYGB7cn0KVmFjY291bnRlZF9hbGwgPC0gVmFjY291bnRlZF9mdW4oImVmYV91c19hZHVsdHMiKSAlPiUKICBmdWxsX2pvaW4oVmFjY291bnRlZF9mdW4oImVmYV9naF9hZHVsdHMiKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfdGhfYWR1bHRzIikpICU+JQogIGZ1bGxfam9pbihWYWNjb3VudGVkX2Z1bigiZWZhX2NoX2FkdWx0cyIpKSAlPiUKICBmdWxsX2pvaW4oVmFjY291bnRlZF9mdW4oImVmYV92dF9hZHVsdHMiKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfdXNfY2hpbGRyZW4iKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfZ2hfY2hpbGRyZW4iKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfdGhfY2hpbGRyZW4iKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfY2hfY2hpbGRyZW4iKSkgJT4lCiAgZnVsbF9qb2luKFZhY2NvdW50ZWRfZnVuKCJlZmFfdnRfY2hpbGRyZW4iKSkKYGBgCgpgYGB7cn0KVmFjY291bnRlZF9hbGwgJT4lCiAgZmlsdGVyKG1ldHJpYyAlaW4lIGMoIlByb3BvcnRpb24gVmFyIiwgIlByb3BvcnRpb24gRXhwbGFpbmVkIikpICU+JQogIGdhdGhlcihmYWN0b3IsIHZhbHVlLCBzdGFydHNfd2l0aCgiRiIpKSAlPiUKICBtdXRhdGUodmFsdWUgPSByb3VuZCh2YWx1ZSwgMikpICU+JQogIHNwcmVhZChjb3VudHJ5LCB2YWx1ZSkgJT4lCiAgYXJyYW5nZShhZ2VfZ3JvdXAsIGZhY3RvciwgbWV0cmljKQpgYGAKYGBge3J9ClZhY2NvdW50ZWRfYWxsICU+JQogIGZpbHRlcihtZXRyaWMgPT0gIkN1bXVsYXRpdmUgVmFyIikgJT4lCiAgZ2F0aGVyKGZhY3RvciwgdmFsdWUsIHN0YXJ0c193aXRoKCJGIikpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIGFnZV9ncm91cCkgJT4lCiAgdG9wX24oMSwgdmFsdWUpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUodmFsdWUgPSByb3VuZCh2YWx1ZSwgMikpICU+JQogIHNlbGVjdChtZXRyaWMsIGNvdW50cnksIGFnZV9ncm91cCwgdmFsdWUpICU+JQogIHNwcmVhZChjb3VudHJ5LCB2YWx1ZSkgJT4lCiAgYXJyYW5nZShhZ2VfZ3JvdXAsIG1ldHJpYykKYGBgCgo=